实际案例:
实现一个装饰器,它用来检查被装饰函数的参数类型。装饰器可以通过参数指明函数参数的类型,调用时如果检测出类型不匹配则抛出异常。
# 不同的函数需要做不同的类型检查,通过参数为他们每一个定制化一个装饰器。
# @后面整体是一个函数的调用,相当于type_assert函数它会返回一个装饰器。
# 带参数的装饰器可以看成生产装饰器的工厂。
@type_assert(str, int, int)
def f(a, b, c):
... ...
@type_assert(y=list) # 关键字传惨形式
def g(x, y):
... ...
解决方案:
提取函数签名:inspect.signature()
带参数的装饰器,也就是根据参数定制化一个装饰器,可以看成生产装饰器的工厂。
每次调用type_assert,返回一个特定的装饰器,然后用它去装饰其他函数。
2、代码演示# _*_ encoding:utf-8 _*_
from inspect import signature
# 定义带参数装饰器,实现参数类型检查功能
def type_assert(*ty_args, **ty_kwargs):
"""生产装饰器工厂,内部定义一个装饰器"""
# 获取函数参数和它类型之间的映射关系
def decorator(func):
# 获取函数参数列表
sig = signature(func)
# 奖建立类型映射和参数名字,绑定部分检查
b_types = sig.bind_partial(*ty_args, **ty_kwargs).arguments
# 根据参数列表定制化出来一个装饰器
def wrapper(*args, **kwargs):
dic = sig.bind(*args, **kwargs).arguments.items()
for name, obj in dic:
# 只有在映射关系中才做类型检查
if name in b_types:
# 检查类型,如果类型不对抛出异常
if not isinstance(obj, b_types[name]):
raise TypeError('"%s" must be "%s"'
% (name, b_types[name]))
return func(*args, **kwargs)
return wrapper
# 返回装饰器
return decorator
# 测试代码
@type_assert(int, str, list)
def f(a, b, c):
print(a, b, c)
f(1, 'abc', [1, 2, 3])
# 报错提示b必须是一个str
f(1, 2, [1, 2, 3])



