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编辑  收藏  举报

导航