# 利用装饰器对函数参数强制执行类型检查
# 利用装饰器对函数参数强制执行类型检查
"""
>>> @typeassert(int, z=int)
... def spam(x, y, z=42):
... print(x, y, z)
...
>>> spam(1, 2, 3)
1 2 3
>>> spam(1, 'hello', 3)
1 hello 3
>>> spam(1, 'hello', 'world')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "contract.py", line 33, in wrapper
TypeError: Argument z must be <class 'int'>
"""
from inspect import signature
from functools import wraps
def typeassert(*ty_args, **ty_kwargs):
def decorate(func):
# If in optimized mode, disable type checking
if not __debug__:
return func
# Map function argument names to supplied types
sig = signature(func)
bound_types = sig.bind_partial(*ty_args, **ty_kwargs).arguments
@wraps(func)
def wrapper(*args, **kwargs):
bound_values = sig.bind(*args, **kwargs)
print(f"{bound_types}\n{bound_values.arguments}")
# Enforce type assertions across supplied arguments
for name, value in bound_values.arguments.items():
if name in bound_types:
if not isinstance(value, bound_types[name]):
raise TypeError(
'Argument {} must be {}'.format(name, bound_types[name])
)
return func(*args, **kwargs)
return wrapper
return decorate
@typeassert(int, z=int)
def spam(x, y, z=42):
print(x, y, z)
spam(1, 2, 3)
"""
OrderedDict([('x', <class 'int'>), ('z', <class 'int'>)])
OrderedDict([('x', 1), ('y', 2), ('z', 3)])
"""