

Python Programming
Python provides several ways to check the type of variables or objects, each with its own features and best-use cases. In this section we provide an overview of each of the type checking approaches available in Python. In the next section we drill into the "collectables.abc" module which checks behaviours (like "Iterable") which is an alternative way to approach type checking. In the final section we look at the Types module which provides checks for functions and some abstract types not easily distinguished using type() or isinstance(). Here's a rundown of the main approaches:
What it does: Returns the exact type of an object.
Usage:
x = 10
print(type(x)) # Output: <class 'int'>
Features:
Precise and directly shows the object's type.
Can be used for exact type comparisons:
if type(x) is int:
print("x is an integer")
Limitations:
Not suited for checking inheritance or behaviours, as it doesn't account for subclasses or behaviour.
What it does: Checks if an object is an instance of a class (or subclass).
Usage:
x = 10 print(isinstance(x, int)) # Output: True
Features:
Supports inheritance: returns True if the object is of the given type or a subclass of it.
Can check against multiple types at once:
if isinstance(x, (int, float)):
print("x is a number")
Limitations:
More general; does not distinguish between direct class instances and subclasses.
issubclass() FunctionWhat it does: Checks if a class is a subclass of another class.
Usage:
class A: pass
class B(A): pass
print(issubclass(B, A)) # Output: True
Features:
Works with class relationships, useful for validating type hierarchies.
Limitations:
Only works for classes, not objects.
__class__ AttributeWhat it does: Directly accesses the class of an object.
Usage:
x = [1, 2, 3]
print(x.__class__) # Output: <class 'list'>
Features:
Provides the same result as type() but more programmatically accessible.
Limitations:
Typically less readable than type() for quick checks.
collections.abc for Abstract Base ClassesWhat it does: Checks if an object implements certain behaviors (e.g., if it's iterable, a mapping, etc.).
Usage:
from collections.abc import Iterable
x = [1, 2, 3]
print(isinstance(x, Iterable)) # Output: True
Features:
Useful for duck typing—checks if an object implements a specific interface rather than its type.
Limitations:
Doesn't distinguish between types, focuses on behavior.
type hints (PEP 484)What it does: Provides type annotations for functions, variables, and classes.
Usage:
def add(a: int, b: int) -> int:
return a + b
Features:
Improves code readability and maintainability.
Tools like mypy and IDEs can verify types statically.
Limitations:
Not enforced at runtime; purely for documentation and static analysis.
callable()What it does: Checks if an object is callable (e.g., a function or class instance with a __call__ method).
Usage:
def func(): pass
print(callable(func)) # Output: True
Features:
Helps check if an object can be invoked like a function.
Limitations:
Doesn't identify the exact type of callable (e.g., function vs lambda).
What it does: Implements checks using hasattr() or custom logic.
Usage:
class MyClass:
def method(self): pass
x = MyClass()
if hasattr(x, "method"):
print("x has a 'method' attribute")
Features:
Highly flexible and allows checking for specific attributes or methods.
Limitations:
Not a standard type check, more of a structural or feature-based check.
types ModuleWhat it does: Provides names for common Python types like FunctionType, GeneratorType, etc.
Usage:
from types import FunctionType
def func(): pass
print(isinstance(func, FunctionType)) # Output: True
Features:
Useful for distinguishing between specific built-in types (e.g., functions vs methods).
Limitations:
Requires importing types and is more specialized.
Exact Type Check: Use type() when you need to verify the specific class.
Duck Typing or Behavior: Use isinstance() with collections.abc for more flexible checks.
Custom Needs: Combine hasattr() or callable() for checking behaviors beyond standard types.
Static Typing: Use type hints (PEP 484) to improve readability and leverage tools like mypy for checks.
The collections.abc module in Python provides a set of abstract base classes (ABCs) that define common behaviors for container types and other objects. These ABCs allow you to check whether an object implements specific behaviors or interfaces, such as being iterable, a mapping, or a sequence. Here's a breakdown of the key behaviors you can check using collections.abc:
Container: Checks if an object supports the in operator.
from collections.abc import Container
print(isinstance([1, 2, 3], Container)) # Output: True
Iterable: Checks if an object can be iterated over (implements __iter__).
python
from collections.abc import Iterable
print(isinstance([1, 2, 3], Iterable)) # Output: True
Iterator: Checks if an object is an iterator (implements __iter__ and __next__).
from collections.abc import Iterator
print(isinstance(iter([1, 2, 3]), Iterator)) # Output: True
Sequence: Checks if an object supports sequence operations like indexing and slicing.
from collections.abc import Sequence
print(isinstance([1, 2, 3], Sequence)) # Output: True
Mapping: Checks if an object behaves like a dictionary (supports key-value pairs).
from collections.abc import Mapping
print(isinstance({"a": 1}, Mapping)) # Output: True
MutableMapping: Checks if a mapping object is mutable (supports adding/removing items).
from collections.abc import MutableMapping
print(isinstance({"a": 1}, MutableMapping)) # Output: True
Set: Checks if an object behaves like a set (supports set operations like union, intersection).
from collections.abc import Set
print(isinstance({1, 2, 3}, Set)) # Output: True
MutableSet: Checks if a set object is mutable (supports adding/removing elements).
python
from collections.abc import MutableSet
print(isinstance({1, 2, 3}, MutableSet)) # Output: True
MappingView: Checks if an object is a view of a mapping (e.g., dict.keys() or dict.values()).
from collections.abc import MappingView
print(isinstance({"a": 1}.keys(), MappingView)) # Output: True
Callable: Checks if an object is callable (e.g., a function or an object with __call__).
from collections.abc import Callable
print(isinstance(lambda x: x, Callable)) # Output: True
Sized: Checks if an object has a length (implements __len__).
from collections.abc import Sized
print(isinstance([1, 2, 3], Sized)) # Output: True
Hashable: Checks if an object is hashable (implements __hash__).
from collections.abc import Hashable
print(isinstance(42, Hashable)) # Output: True
Awaitable: Checks if an object can be awaited (implements __await__).
from collections.abc import Awaitable
async def example(): pass
print(isinstance(example(), Awaitable)) # Output: True
Coroutine: Checks if an object is a coroutine (implements __await__ and send).
from collections.abc import Coroutine
async def example(): pass
print(isinstance(example(), Coroutine)) # Output: True
AsyncIterable: Checks if an object supports asynchronous iteration (implements __aiter__).
from collections.abc import AsyncIterable
class AsyncGen:
async def __aiter__(self): yield 1
print(isinstance(AsyncGen(), AsyncIterable)) # Output: True
AsyncIterator: Checks if an object is an asynchronous iterator (implements __anext__).
from collections.abc import AsyncIterator
class AsyncGen:
async def __aiter__(self): yield 1
print(isinstance(AsyncGen().__aiter__(), AsyncIterator)) # Output: True
Buffer: Checks if an object supports the buffer protocol (e.g., memoryview).
from collections.abc import Buffer
print(isinstance(memoryview(b"data"), Buffer)) # Output: True
collections.abc?Duck Typing: Focuses on behavior rather than exact types.
Extensibility: You can create your own classes that inherit from these ABCs to ensure they conform to specific behaviors.
Readability: Makes it clear what behaviors your code expects from objects.
The types module in Python provides names for many specific object types, especially those related to functions, modules, and other built-in constructs. Here's a comprehensive list of the types you can check using the types module, along with examples:
FunctionType: Represents a standard Python function.
from types import FunctionType
def my_function():
pass
print(isinstance(my_function, FunctionType)) # Output: True
LambdaType: Represents a lambda function (alias for FunctionType).
from types import LambdaType
my_lambda = lambda x: x + 1
print(isinstance(my_lambda, LambdaType)) # Output: True
BuiltinFunctionType: Represents built-in functions like len or print.
from types import BuiltinFunctionType
print(isinstance(len, BuiltinFunctionType)) # Output: True
BuiltinMethodType: Represents built-in methods of objects (e.g., dict.get).
from types import BuiltinMethodType
my_dict = {}
print(isinstance(my_dict.get, BuiltinMethodType)) # Output: True
GeneratorType: Represents a generator object.
from types import GeneratorType
def my_generator():
yield 1
gen = my_generator()
print(isinstance(gen, GeneratorType)) # Output: True
CoroutineType: Represents a coroutine object.
from types import CoroutineType
async def my_coroutine():
pass
coro = my_coroutine()
print(isinstance(coro, CoroutineType)) # Output: True
AsyncGeneratorType: Represents an asynchronous generator object.
from types import AsyncGeneratorType
async def my_async_generator():
yield 1
async_gen = my_async_generator()
print(isinstance(async_gen, AsyncGeneratorType)) # Output: True
CodeType: Represents a code object (compiled Python code).
from types import CodeType
def my_function():
pass
print(isinstance(my_function.__code__, CodeType)) # Output: True
FrameType: Represents a stack frame object.
import sys
from types import FrameType
frame = sys._getframe()
print(isinstance(frame, FrameType)) # Output: True
ModuleType: Represents a module object.
import math
from types import ModuleType
print(isinstance(math, ModuleType)) # Output: True
ClassType: Represents old-style classes in Python 2 (not used in Python 3).
MethodType: Represents instance methods of a class.
from types import MethodType
class MyClass:
def my_method(self):
pass
obj = MyClass()
print(isinstance(obj.my_method, MethodType)) # Output: True
UnboundMethodType: Represents unbound methods in Python 2 (not used in Python 3).
TracebackType: Represents a traceback object.
import sys
from types import TracebackType
try:
1 / 0
except ZeroDivisionError:
tb = sys.exc_info()[2]
print(isinstance(tb, TracebackType)) # Output: True
EllipsisType: Represents the Ellipsis object (...).
from types import EllipsisType
print(isinstance(..., EllipsisType)) # Output: True
NotImplementedType: Represents the NotImplemented object.
from types import NotImplementedType
print(isinstance(NotImplemented, NotImplementedType)) # Output: True
MappingProxyType: Represents a read-only view of a dictionary.
from types import MappingProxyType
my_dict = {"a": 1}
proxy = MappingProxyType(my_dict)
print(isinstance(proxy, MappingProxyType)) # Output: True
SimpleNamespace: Represents a simple object for attribute storage.
from types import SimpleNamespace
obj = SimpleNamespace(a=1, b=2)
print(isinstance(obj, SimpleNamespace)) # Output: True
The types module is particularly useful for checking specific object types that aren't easily distinguishable using type() or isinstance(). It provides a way to identify Python's internal and specialized types, such as functions, generators, coroutines, and more.