types — Dynamic Type Creation and Names for Built-in Types
📚 Official Documentation & Resources
Primary Official Sources (REQUIRED)
- Python Official Library Documentation: https://docs.python.org/3/library/types.html
- Python Official Tutorial: https://docs.python.org/3/tutorial/index.html
- Module Source Code: https://github.com/python/cpython/blob/main/Lib/types.py
Additional Authoritative Sources
- PEP 585: Type Hinting Generics In Standard Collections
- PEP 560: Core support for typing module and generic types
- Real Python - Python Type Checking: https://realpython.com/python-type-checking/
- GeeksforGeeks - Python Types: https://www.geeksforgeeks.org/python-types-module/
- Python Module of the Week (PyMOTW) - types: https://pymotw.com/3/types/
- Stack Overflow types questions: https://stackoverflow.com/questions/tagged/python+types
- "Effective Python" by Brett Slatkin - Items on metaclasses and type introspection
IMPORTANT: Examples in this guide are adapted from the official Python documentation at https://docs.python.org/3/library/types.html
Overview
The types module defines utility functions and classes for working with types and dynamic type creation. This module provides names for types that are not directly accessible as built-ins, such as the type of generator functions, and utilities for creating new types dynamically. It's particularly useful for metaprogramming, type introspection, and creating dynamic code structures.
The module has been available since early Python versions and has been enhanced over time with additional type utilities, especially for supporting modern Python features like async/await, generics, and type annotations.
🎯 Key Characteristics
- Type Introspection: Access to internal Python types not available as built-ins
- Dynamic Type Creation: Utilities for creating types at runtime
- Function Types: Support for various function and method types
- Generator Support: Types for generators, coroutines, and async iterators
- Namespace Utilities: Dynamic namespace creation and manipulation
- Metaclass Support: Utilities for working with metaclasses and type creation
🔧 Prerequisites and Setup
Python Version Compatibility
- Minimum Python version required: Python 2.0+ (basic functionality)
- Async support: Python 3.5+ (coroutine types)
- Enhanced features: Python 3.7+ (additional type utilities)
- Latest improvements: Python 3.9+ (generic alias support)
Installation and Imports
# Standard library (no installation needed)
import types
from types import SimpleNamespace, MethodType, FunctionType
📚 Basic Usage
Official Documentation Examples
Source: All examples adapted from https://docs.python.org/3/library/types.html
Simple Example
import types
# Create a simple namespace
namespace = types.SimpleNamespace()
namespace.x = 1
namespace.y = 2
print(f"Namespace: x={namespace.x}, y={namespace.y}") # Namespace: x=1, y=2
# Check function types
def my_function():
pass
print(isinstance(my_function, types.FunctionType)) # True
print(isinstance(len, types.BuiltinFunctionType)) # True
# Create a method dynamically
class MyClass:
pass
def new_method(self):
return "Hello from dynamic method!"
MyClass.dynamic_method = new_method
obj = MyClass()
print(obj.dynamic_method()) # Hello from dynamic method!
Core Methods/Functions
import types
# SimpleNamespace usage (from official docs)
ns = types.SimpleNamespace(x=1, y=2, z=3)
print(ns) # namespace(x=1, y=2, z=3)
print(ns.x) # 1
# Modify namespace
ns.w = 4
del ns.z
print(ns) # namespace(x=1, y=2, w=4)
# Type checking utilities (from official docs)
def regular_function():
return "regular"
def generator_function():
yield 1
async def coroutine_function():
return "coroutine"
print(isinstance(regular_function, types.FunctionType)) # True
print(isinstance(generator_function(), types.GeneratorType)) # True
print(isinstance(coroutine_function(), types.CoroutineType)) # True
Common Patterns
# Pattern 1: Dynamic class creation (from official docs)
import types
def dynamic_method(self):
return f"Hello from {self.__class__.__name__}!"
# Create class dynamically
DynamicClass = types.new_class(
'DynamicClass',
(object,),
{},
lambda ns: ns.update({'dynamic_method': dynamic_method})
)
obj = DynamicClass()
print(obj.dynamic_method()) # Hello from DynamicClass!
# Pattern 2: Module creation at runtime (from official docs)
module = types.ModuleType('dynamic_module')
module.variable = "Dynamic content"
module.function = lambda: "Dynamic function"
print(module.variable) # Dynamic content
print(module.function()) # Dynamic function
# Pattern 3: Method binding (from official docs)
class Calculator:
def __init__(self, value):
self.value = value
def add_method(self, x):
return self.value + x
# Bind method to class
Calculator.add = add_method
calc = Calculator(10)
print(calc.add(5)) # 15
# Bind method to instance
def multiply_method(self, x):
return self.value * x
calc.multiply = types.MethodType(multiply_method, calc)
print(calc.multiply(3)) # 30
🔧 types API Reference
Core Type Objects
| Type | Description | Example |
|---|---|---|
FunctionType | Type of user-defined functions | isinstance(func, types.FunctionType) |
LambdaType | Type of lambda functions (alias for FunctionType) | isinstance(lambda: None, types.LambdaType) |
MethodType | Type of bound methods | isinstance(obj.method, types.MethodType) |
BuiltinFunctionType | Type of built-in functions | isinstance(len, types.BuiltinFunctionType) |
BuiltinMethodType | Type of built-in methods | isinstance([].append, types.BuiltinMethodType) |
Generator and Coroutine Types
| Type | Description | Example |
|---|---|---|
GeneratorType | Type of generator objects | isinstance((x for x in []), types.GeneratorType) |
CoroutineType | Type of coroutine objects | isinstance(async_func(), types.CoroutineType) |
AsyncGeneratorType | Type of async generator objects | isinstance(async_gen(), types.AsyncGeneratorType) |
Class and Module Types
| Type | Description | Example |
|---|---|---|
ModuleType | Type of modules | isinstance(sys, types.ModuleType) |
CodeType | Type of code objects | isinstance(func.__code__, types.CodeType) |
FrameType | Type of frame objects | isinstance(sys._getframe(), types.FrameType) |
TracebackType | Type of traceback objects | isinstance(tb, types.TracebackType) |
Utility Classes and Functions
| Function/Class | Description | Example |
|---|---|---|
SimpleNamespace | Simple namespace class | types.SimpleNamespace(x=1, y=2) |
new_class(name, bases, kwds, exec_body) | Create class dynamically | types.new_class('MyClass', (), {}) |
prepare_class(name, bases, kwds) | Prepare class namespace | Advanced metaclass use |
resolve_bases(bases) | Resolve MRO base classes | Metaclass implementation |
Detailed Method Examples
SimpleNamespace Usage
import types
# Official docs example: SimpleNamespace
# Create namespace with initial attributes
config = types.SimpleNamespace(
debug=True,
database_url="localhost:5432",
timeout=30
)
print(config.debug) # True
print(config.database_url) # localhost:5432
# Modify attributes
config.debug = False
config.new_setting = "value"
# Convert to dict
settings_dict = vars(config)
print(settings_dict) # {'debug': False, 'database_url': 'localhost:5432', 'timeout': 30, 'new_setting': 'value'}
# Create from dict
data = {'x': 10, 'y': 20}
point = types.SimpleNamespace(**data)
print(f"Point: ({point.x}, {point.y})") # Point: (10, 20)
Dynamic Class Creation
import types
# Official docs example: new_class function
def class_body(namespace):
namespace['class_variable'] = "Hello"
def instance_method(self):
return f"Instance method called on {self}"
namespace['instance_method'] = instance_method
# Create class dynamically
DynamicClass = types.new_class(
'DynamicClass',
(object,), # base classes
{}, # keyword arguments to metaclass
class_body # function to populate namespace
)
# Use the dynamic class
obj = DynamicClass()
print(obj.class_variable) # Hello
print(obj.instance_method()) # Instance method called on <__main__.DynamicClass object at 0x...>
# Equivalent to:
class RegularClass:
class_variable = "Hello"
def instance_method(self):
return f"Instance method called on {self}"
Method Binding and Types
import types
# Official docs example: Method types and binding
class MyClass:
def __init__(self, value):
self.value = value
def instance_method(self):
return f"Instance method: {self.value}"
obj = MyClass("test")
# Different method types
unbound_method = MyClass.instance_method
bound_method = obj.instance_method
print(isinstance(unbound_method, types.FunctionType)) # True
print(isinstance(bound_method, types.MethodType)) # True
# Create method dynamically
def new_method(self, multiplier):
return self.value * multiplier
# Bind to instance
obj.dynamic_method = types.MethodType(new_method, obj)
print(obj.dynamic_method(3)) # testtesttest
# Bind to class
MyClass.class_method = new_method
obj2 = MyClass("hello")
print(obj2.class_method(2)) # hellohello
Module Creation and Manipulation
import types
import sys
# Official docs example: Dynamic module creation
module_name = 'dynamic_utilities'
utilities = types.ModuleType(module_name)
# Add attributes to module
utilities.PI = 3.14159
utilities.E = 2.71828
def calculate_circle_area(radius):
return utilities.PI * radius ** 2
utilities.calculate_circle_area = calculate_circle_area
# Add module to sys.modules for importing
sys.modules[module_name] = utilities
# Now can import it
import dynamic_utilities
print(dynamic_utilities.calculate_circle_area(5)) # 78.53975
# Module introspection
print(isinstance(utilities, types.ModuleType)) # True
print(utilities.__name__) # dynamic_utilities
Type Checking and Introspection
import types
import inspect
# Official docs example: Type checking utilities
def regular_function(x):
return x * 2
def generator_function():
for i in range(3):
yield i
async def async_function():
return "async result"
class MyClass:
def method(self):
pass
obj = MyClass()
# Function type checking
print(isinstance(regular_function, types.FunctionType)) # True
print(isinstance(lambda x: x, types.LambdaType)) # True (alias for FunctionType)
print(isinstance(len, types.BuiltinFunctionType)) # True
print(isinstance(obj.method, types.MethodType)) # True
# Generator and coroutine checking
gen = generator_function()
coro = async_function()
print(isinstance(gen, types.GeneratorType)) # True
print(isinstance(coro, types.CoroutineType)) # True
# Code object inspection
code = regular_function.__code__
print(isinstance(code, types.CodeType)) # True
print(f"Function name: {code.co_name}") # Function name: regular_function
print(f"Argument count: {code.co_argcount}") # Argument count: 1
Important Notes
Performance Considerations
- Dynamic type creation has overhead compared to static class definition
SimpleNamespaceis faster than creating custom classes for simple data containers- Type checking with
isinstance()is generally fast for built-in types - Frame introspection can be expensive and should be used sparingly
Memory Usage
import types
import sys
# SimpleNamespace vs dict memory comparison
data = {'a': 1, 'b': 2, 'c': 3}
namespace = types.SimpleNamespace(**data)
print(f"Dict size: {sys.getsizeof(data)} bytes")
print(f"SimpleNamespace size: {sys.getsizeof(namespace)} bytes")
# SimpleNamespace typically uses slightly more memory but provides attribute access
Common Gotchas
import types
# Gotcha 1: Function vs Lambda type
def func(): pass
lamb = lambda: None
# These are the same type!
print(types.FunctionType is types.LambdaType) # True
print(isinstance(func, types.LambdaType)) # True
print(isinstance(lamb, types.FunctionType)) # True
# Gotcha 2: Method binding
class MyClass:
def method(self): pass
obj = MyClass()
# Unbound vs bound methods
unbound = MyClass.method # Function type
bound = obj.method # Method type
print(isinstance(unbound, types.FunctionType)) # True
print(isinstance(bound, types.MethodType)) # True
# Gotcha 3: SimpleNamespace equality
ns1 = types.SimpleNamespace(x=1, y=2)
ns2 = types.SimpleNamespace(x=1, y=2)
print(ns1 == ns2) # False - they're different objects
print(vars(ns1) == vars(ns2)) # True - same content
Best Practices
# 1. Use SimpleNamespace for configuration and data containers
config = types.SimpleNamespace(
debug=True,
timeout=30,
max_retries=3
)
# 2. Type checking patterns
def process_callable(func):
if isinstance(func, (types.FunctionType, types.MethodType)):
return func()
elif isinstance(func, types.BuiltinFunctionType):
return func()
else:
raise TypeError("Expected callable")
# 3. Dynamic class creation for factories
def create_model_class(name, fields):
def __init__(self, **kwargs):
for field in fields:
setattr(self, field, kwargs.get(field))
def __repr__(self):
field_strs = [f"{field}={getattr(self, field, None)}" for field in fields]
return f"{name}({', '.join(field_strs)})"
return types.new_class(
name,
(object,),
{},
lambda ns: ns.update({'__init__': __init__, '__repr__': __repr__})
)
# 4. Safe frame inspection
def safe_get_caller_name():
try:
frame = sys._getframe(1)
return frame.f_code.co_name
except (AttributeError, ValueError):
return "unknown"
Thread Safety
- Type objects themselves are thread-safe and immutable
SimpleNamespaceobjects are not thread-safe for concurrent modification- Dynamic class creation should generally be done at module load time
- Frame inspection is generally safe but can be affected by thread switches
Integration with Other Modules
import types
import inspect
import typing
# With inspect module
def analyze_function(func):
if isinstance(func, types.FunctionType):
sig = inspect.signature(func)
print(f"Function: {func.__name__}")
print(f"Parameters: {list(sig.parameters.keys())}")
print(f"Annotations: {func.__annotations__}")
# With typing module
def create_typed_namespace(**kwargs) -> types.SimpleNamespace:
return types.SimpleNamespace(**kwargs)
# With dataclasses (alternative approach)
from dataclasses import dataclass
@dataclass
class TypedConfig:
debug: bool = False
timeout: int = 30
# SimpleNamespace for untyped, dataclass for typed configurations
Related Modules
- inspect: For detailed object introspection and signature analysis
- typing: For type hints and generic type support
- abc: For abstract base classes and interface definition
- dataclasses: For structured data classes (alternative to SimpleNamespace)
- collections: For specialized container types and named tuples