Argument Type Handling
Introduction to Type Checking Decorators
Type checking decorators provide a powerful mechanism to validate function arguments dynamically, ensuring type safety and preventing potential runtime errors.
Basic Type Validation Decorator
def validate_types(*types, **type_kwargs):
def decorator(func):
def wrapper(*args, **kwargs):
## Validate positional arguments
for (arg, expected_type) in zip(args, types):
if not isinstance(arg, expected_type):
raise TypeError(f"Argument must be {expected_type}")
## Validate keyword arguments
for (name, expected_type) in type_kwargs.items():
if name in kwargs and not isinstance(kwargs[name], expected_type):
raise TypeError(f"{name} must be {expected_type}")
return func(*args, **kwargs)
return wrapper
return decorator
@validate_types(int, int)
def add_numbers(a, b):
return a + b
## Valid usage
result = add_numbers(5, 3)
## This will raise a TypeError
## result = add_numbers('5', 3)
Advanced Type Handling Strategies
Flexible Type Checking
def flexible_type_check(*allowed_types):
def decorator(func):
def wrapper(*args, **kwargs):
for arg in args:
if not any(isinstance(arg, t) for t in allowed_types):
raise TypeError(f"Argument must be one of {allowed_types}")
return func(*args, **kwargs)
return wrapper
return decorator
@flexible_type_check(int, float)
def process_number(x):
return x * 2
Type Handling Patterns
Pattern |
Description |
Use Case |
Strict Typing |
Exact type match |
Critical systems |
Flexible Typing |
Multiple allowed types |
Generic processing |
Optional Typing |
Allow None or specific types |
Nullable parameters |
Decorator Type Checking Flow
graph TD
A[Function Call] --> B{Type Validation}
B -->|Pass| C[Execute Original Function]
B -->|Fail| D[Raise TypeError]
C --> E[Return Result]
Complex Type Validation Example
def validate_complex_types(type_spec):
def decorator(func):
def wrapper(*args, **kwargs):
for (arg, spec) in zip(args, type_spec):
## Support nested type checking
if isinstance(spec, (list, tuple)):
if not isinstance(arg, spec[0]) or len(arg) != spec[1]:
raise TypeError(f"Invalid argument type or length")
elif not isinstance(arg, spec):
raise TypeError(f"Invalid argument type")
return func(*args, **kwargs)
return wrapper
return decorator
@validate_complex_types([list, 3])
def process_fixed_list(data):
return sum(data)
## Usage
result = process_fixed_list([1, 2, 3])
Best Practices
- Use type hints for documentation
- Combine with runtime type checking
- Handle edge cases gracefully
- Provide clear error messages
Explore more advanced type handling techniques in LabEx Python programming courses.