Python is dynamically typed: you don't declare a variable's type, and a variable can be reassigned to a value of a different type entirely.
age = 25 # int
price = 19.99 # float
name = "Rahim" # str
is_active = True # bool (note the capital T/F)
nothing = None # Python's null equivalent
age = "twenty-five" # legal — age now refers to a str instead of an int
print(type(age)) # <class 'str'>
A Python variable is really a name bound to an object rather than a labeled memory box holding a fixed type — age = 25 creates an int object and binds the name age to it; age = "twenty-five" doesn't convert anything, it simply rebinds age to a brand-new str object, leaving the old int to be garbage-collected once nothing else references it.
type(x) returns an object's exact type, and isinstance(x, int) checks whether an object is of a given type (or a subclass of it) — prefer isinstance() for actual type-checking logic in real code, since it correctly handles inheritance.
None is Python's equivalent of null/nil — it represents the deliberate absence of a value, and is checked with if x is None: (using is, not ==, since None is a singleton and identity comparison is both correct and slightly faster).