分析掌握python装饰器(二)

看完(一)后,想必已经对装饰器有了一个基本的概念。在(二)中,我将会对装饰器的一些高级用法做一点研究记录。

1、装饰器带其他参数

接着上面的例子,我们希望并不是每个人都有权限去使用这个计算函数,只有特定的人才可以。

  def checktype(personname=None):
    def decorate(func):
        def wrapper(*args,**kwargs):
            count = 0
            if personname == 'ghy':
                str = []
                for n in args:
                    if not isinstance(n,(int,float)):
                        log= '{}的类型无法计算'.format(n)
                        str.append(log)
                        count += 1
                if count == 0:
                    return func(*args,**kwargs)
                else:
                    print(str)
            else:
                print('{}, you are limited'.format(personname))
        return  wrapper
    return decorate

@checktype('test')
def calfunc(*numbers,sign=None):
    if sign is None:
        return 'please input a sign'
    if hasattr(case['+'], '__call__'):
        add=case['+']
        return print(add(*numbers))
#调用
calfunc('a','b',sign='+') #输出 test you  are limited

2、自定义装饰器属性

有时候我们会想通过为装饰器定义一些属性,来修改其中的参数
如上个例子所示,我们想通过属性来修改personname的值

from functools import wraps,partial
#将函数属性附加到包装函数上
#使用partial函数
#from functools import partial
#partial 函数的作用就是
#把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。
#第一个参数为原函数。
def add_attr(obj,func=None):
    if func is None:
        return partial(add_attr,obj)
    setattr(obj,func.__name__,func)
    return func

#装饰器
def checktype(personname=None):
    def decorate(func):
        #保留原函数的一些元数据 比如 函数名 不加 calfunc.__name__输出 wrapper
        @wraps(func)
        def wrapper(*args,**kwargs):
            count = 0
            if personname == 'ghy':
                str = []
                for n in args:
                    if not isinstance(n,(int,float)):
                        log= '{}的类型无法计算'.format(n)
                        str.append(log)
                        count += 1
                if count == 0:
                    return func(*args,**kwargs)
                else:
                    print(str)
            else:
                print('{}, you are limited'.format(personname))

        @add_attr(wrapper) #相当于 add_attr(wrapper)()=>add_attr(wrapper,sef_modifypersonname)
        def sef_modifypersonname(newname):
            nonlocal personname  # 如果没有这个,下面一句是在当前作用域内又创建了一个personame
            personname = newname

        return  wrapper
    return decorate
@checktype('test')
def calfunc(*numbers,sign=None):
    if sign is None:
        return 'please input a sign'
    if hasattr(case['+'], '__call__'):
        add=case['+']
        return print(add(*numbers))

calfunc(1,2,sign='+') #输出 test you are limited
calfunc.sef_modifypersonname('ghy')
calfunc(1,2,sign='+') #输出 3

#装饰器解包,调用__wrapped__ 不进入装饰器包装函数
calfunc.sef_modifypersonname('test')
calfunc.__wrapped__(1,2,sign='+') #输出 3

上面一个比较重要的稍微难以理解的点就是@add_attr(wrapper),但其实你只要明白了

装饰器是在代码解释的时候就已经调用执行了

也就是说我们的装饰器处的代码,我们可以心里自动给它默认为

sef_modifypersonname=add_attr(wrapper)(sef_modifypersonname)

还有一个即 @wraps(func)注释已经写的很清楚了,保留原函数的元数据。

    原文作者:Wantobetter
    原文地址: https://www.jianshu.com/p/8f1068b46974
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞