9-3 如何定义带参数的装饰器
在python2中没有获取函数签名模块,在python3中from inspect import signature可以获取函数签名
一、介绍使用方法
>>>from inspect import signature >>>def f(a,b,c=1):pass >>>sig = signature(f)
1、sig.parameters包括参数的字典
>>>a = sig.parameters[‘a’] #取出参数a的信息 >>>a.name ‘a’
2、a.kind 查看参数属于哪种类型,位置参数还是关键字参数
>>>a.default #查看a的默认值 Inspect._empty #返回,说明a没有默认值 >>>c = sig.parameters[‘c’] #取出参数a的信息 >>>c.default 1
二、创建签名字典
1、sig.bind(str,int,int) 绑定参数对象,a->str , b->int, c->int
bargs = sig.bind(str,int,int)
2、bargs.arguments 它是一个字典,具有参数的字典
>>>bargs.arguments[‘a’] builtins.str >>>bargs.arguments[‘b’] builtins.int
注意,bind()和函数调用一样做参数检查,某些必须传的参数没有传,一样会报错。
3、sig.bind_partial(str) 绑定部分属性
三、实例
from inspect import signature def typeassert(*ty_args,**ty_kargs): #定义一个带参数的装饰器,可带任何参数, #*tyargs,带表不定长参数(元组),**ty_kargs代表关键字参数(字典) def decorator(func): #typeassert是一个装饰器的工厂,它生产装饰器 #typeassert内部定义 一个装饰器decorator #decorator才是一个真正的函数装饰器,接受一个函数参数 #在decorator内部根据typeassert的参数,定制化一个参数 #需要获取到函数参数和类型的映射关系 #func ->a,b #(1)得到函数的签名,有哪些参数,类型信息是在参数*ty_args,**ty_kargs中传过来的 #d = {'a':int,'b'str} #(2)通过这些信息,建立一个映射关系 字典,得到这些信息,在函数调用时就可以做类型检查了。 #1、建立类型映射和参数名字 sig = signature(func) btypes = sig.bind_partial(*ty_args,**ty_kargs).arguments def wrapper(*args,**kargs): #迭代*args,**kargs参数,判断是否在字典d中。在字典中是需要做类型检查的,判断字典中的值是否和类型匹配 #arg in d, instance(arg,d[arg]),判断arg是否是类型的一个实例,如不匹配抛出异常 #2、获得调用时的某一个参数 for name,obj in sig.bind(*args,**kargs).arguments.items():#调用的参数要全部映射 if name in btypes: #类型在字典中时再检查类型 if not isinstance(obj,btypes[name]):#类型不匹配,抛出异常 raise TypeError('%s' must be '%s' %(name,btypes[name])) return func(*args,**kargs) return wrapper #装饰器返回一个内部包裹函数 return decorator #最外层函数返回一个装饰器 @typeassert(int,str,list) def f(a,b,c): print(a,b,c)
测试
f(1,'abc',[1,2,3]) f(1,2,[1,2,3])
输出结果:
posted on 2018-05-10 09:41 石中玉smulngy 阅读(165) 评论(0) 编辑 收藏 举报