Values
Python's built-in scalar types: int, float, str, bool, None, and bytes - with identity versus equality.
Python has six built-in scalar types: int, float, str, bool, None, and bytes. Everything in Python is an object, so every value carries its type with it. type(x) returns the object's class; isinstance(x, SomeType) tests membership, including subclasses.
Each scalar type has a literal form. type() returns the class of any value.
type(42) # <class 'int'>
type(3.14) # <class 'float'>
type("hi") # <class 'str'>
type(True) # <class 'bool'>
type(None) # <class 'NoneType'>
type(b"bytes") # <class 'bytes'>isinstance(x, T) is the idiomatic way to check a value's type at runtime because it respects inheritance. bool is a subclass of int, so isinstance(True, int) is True. This can produce surprises if you expect the check to be strict.
isinstance(42, int) # True
isinstance(3.14, float) # True
isinstance("hi", str) # True
# bool is a subclass of int
isinstance(True, int) # True <- not False
isinstance(True, bool) # True== compares values; is compares identity (whether two names point to the exact same object in memory). Use == for value comparison and is only for None, True, False, and sentinel singletons.
1 == 1.0 # True - same value, different types
1 is 1.0 # False - different objects
x = None
x is None # True - canonical None check
x == None # True - works, but non-idiomaticIn production
bool is a subclass of int (True == 1, isinstance(True, int) is True) and this leaks into JSON serialisation, sum(), and dict keys - a function expecting an integer silently accepts True. Use is only for None, True, False, and sentinel singletons; use == for value comparison everywhere else.
Enjoyed this? Get more essays on software craft delivered to your inbox.
Subscribe free