Understand the contract
isinstance asks whether an object belongs to a class or one of its subclasses. issubclass asks about classes rather than instances. Their second argument can be a tuple of alternatives, which expresses an either-or check.
These functions respect inheritance, unlike type(value) is SomeType, which tests only an exact type. This distinction matters when callers supply a specialized subclass that should be accepted wherever its parent is accepted.
Follow the runtime behavior
bool is a subclass of int, so isinstance(True, int) is True. Numeric validation may need to exclude bool explicitly. Checking a container class says nothing about its element types.
Parameterized generics such as list[int] cannot be used as ordinary isinstance targets. Validate the container and its elements separately when a runtime data contract is required.
Apply it and practise
Prefer behavior-based interfaces for ordinary polymorphic code. Use runtime type checks when decoding external values or when different representations need deliberately different treatment.
Exercise: write is_integer_list(value) that accepts a list containing only integers and rejects booleans. Test [1, 2], [True], an empty list, and a tuple; decide whether accepting the empty list matches your requirement.
Syntax
isinstance(value, (int, float))
issubclass(Child, Parent)Examples
Respect inheritance
Use isinstance when a specialized object should remain acceptable through its base interface.
class Animal:
pass
class Cat(Animal):
pass
pet = Cat()
print(isinstance(pet, Animal))
print(issubclass(Cat, Animal))
print(type(pet) is Animal)- Cat inherits Animal, so both hierarchy questions succeed. The exact type of pet is Cat, which explains the final False.
- Use isinstance when a specialized object should remain acceptable through its base interface.
- Pass a class as the first argument of issubclass; passing pet would raise TypeError.
- Expected output: True True False
Validate numeric input deliberately
Use this predicate before applying a numeric calculation to decoded input.
def is_number(value: object) -> bool:
return isinstance(value, (int, float)) and not isinstance(value, bool)
for value in [3, 2.5, True, "3"]:
print(is_number(value))- The tuple accepts either integer or float. The second condition removes booleans despite their integer inheritance; text is never converted implicitly.
- Use this predicate before applying a numeric calculation to decoded input.
- This contract accepts infinities and NaN floats. Add a finiteness check if the application cannot use them.
- Expected output: True True False False
Check element types
Use this stricter contract when a data format requires plain integer elements.
def integer_list(value: object) -> bool:
return isinstance(value, list) and all(type(item) is int for item in value)
print(integer_list([1, 2]))
print(integer_list([1, "2"]))
print(integer_list([True]))- Short-circuiting prevents iteration unless value is a list. all tests each element, and exact int checks deliberately exclude bool and integer subclasses.
- Use this stricter contract when a data format requires plain integer elements.
- The empty list passes all because there is no counterexample. Exact checks may reject legitimate numeric subclasses.
- Expected output: True False False
Best practices
- Parameterized generics such as list[int] cannot be used as ordinary isinstance targets. Validate the container and its elements separately when a runtime data contract is required.
- Prefer behavior-based interfaces for ordinary polymorphic code. Use runtime type checks when decoding external values or when different representations need deliberately different treatment.
Runtime & versions
Python interpreter. Feature availability depends on the language and runtime version used by your project; consult the official reference below.
Python language reference