zoukankan      html  css  js  c++  java
  • python函数装饰器

    装饰器(Decorators)是Python的一个重要部分。简单地说:他们是修改其它函数的功能的函数。他们有助于让我们的代码更简短,也更Pythonic。

    一切皆对象

    我们可以将一个函数赋值给一个变量

    def hi():
        print("hihi")
    a=hi
    print(a,type(a))
    hi() #调用hi函数,需要加()
    

     运行结果

     在函数中定义函数

    def hi():
        print("hihi")
        def yun():
            return "yunyun"
        print(yun())
    hi()
    #yun()#报错#在hi()函数之外是不能访问的
    

     运行结果

     从函数中返回函数

    def hi(name="xx"):
        print(name)
    
        def he():
            return "xixi"
        return he #返回he相当于返回he()函数
    a=hi() #此时不会调用he(),因为hi()函数中无调用此函数的语句
    print(a,type(a))
    print(a()) #函数调用需要加()  

     运行结果

    将函数作为参数传给另一个函数

    def hi(name="xx"):
        print(name)
    
    def study(a):
        a()
        print("我是study")
    
    study(hi)
    

     运行结果

     第一个装饰器

    下面的代码你看的懂?都是上面刚刚提到的知识点。

    def aa(bb):
        print("我是aa哈")
        def cc():
            print("我是cc吆")
            bb()
            return "cc"
        return cc
    
    def xixi():
        print("我是xixi")
    
    m=aa(xixi) #输出:我是aa哈,
    print(m,type(m)) #m是cc()函数
    print(m()) #我是cc吆,我是xixi,cc函数的返回值  

     运行结果

      

     下面我们使用@来修改上面的代码

    def aa(bb):
        print("我是aa哈")
        def cc():
            print("我是cc吆")
            bb()
            return "cc"
        return cc
    @aa
    def xixi():
        print("我是xixi")
    
    print(xixi()) #等价于aa(xixi)()  

     运行结果

    下面存在一个问题

    print(xixi.__name__) #输出cc  

     这并不是我们想要的!应该输出xixi。这里的函数被cc替代了。它重写了我们函数的名字和注释文档(doctring)。幸运的是Python提供给我们一个简单的函数来解决这个问题,那就是Functools.wraps。我们使用functools.wraps修改上一个例子

    from functools import wraps
    def aa(bb):
        print("我是aa哈")
        @wraps(bb)
        def cc():
            print("我是cc吆")
            bb()
            return "cc"
        return cc
    @aa
    def xixi():
        print("我是xixi")
    
    #print(xixi()) #等价于aa(xixi)()
    print(xixi.__name__)  

     运行结果

     注意:@wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。

    蓝本规范:

    from functools import wraps
    def aa(bb):
        print("我是aa哈")
        @wraps(bb)
        def cc(*args,**kwargs):
            if not can_run:
                return "bb方法不运行"
            return bb(*args,**kwargs)
        return cc
    @aa
    def xixi():
        return "我是xixi"
    
    can_run=False
    print(xixi()) #我是aa哈;bb方法不运行;
    
    # can_run=True
    # print(xixi()) #我是aa哈;我是xixi

    使用场景

      授权(Authorization)

      日志(Logging)

     带参数的装饰器

    来想想这个问题,难道@wraps不也是个装饰器吗?但是,它接收一个参数,就像任何普通的函数能做的那样。那么,为什么我们不也那样做呢?这是因为,当你使用@aa语法时,你是在应用一个以单个函数作为参数的一个包裹函数。记住,Python里每个东西都是一个对象,而且这包括函数!

    在函数中嵌入装饰器

    from functools import wraps
    def aa(name="xiaoxiao"):
        def bb(cc):
            @wraps(cc)
            def dd(*args,**kwargs):
                log=cc.__name__+"被调用"
                print(log)
                return cc(*args,**kwargs)
            return dd
        return bb
    # @aa() #注意与无参的对比,这里多了()
    # def xixi():
    #     return "我是xixi"
    
    @aa(name="dehua")
    def xixi():
        return "我是xixi"
    print(xixi()) #xixi被调用,我是xixi
    

     运行结果

    装饰器类

    没错,装饰器不仅可以是函数,还可以是类,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器主要依靠类的__call__方法,当使用@形式将装饰器附加到函数上时,就会调用此方法。

    class Foo(object):
        def __init__(self, func):
            self._func = func
            #print(self._func)
        def __call__(self):
            print ('class decorator runing')
            self._func()
            print ('class decorator ending')
    @Foo
    def bar():
        print ('bar')
    bar()  

     运行结果

    参考:https://www.runoob.com/w3cnote/python-func-decorators.html

       https://www.runoob.com/w3cnote/python-func-decorators.html

      

    越努力,越幸运!!! good good study,day day up!!!
  • 相关阅读:
    django学习笔记1
    排序多重排序
    06计算列
    填充日期序列
    行,列单元格
    读取excel文件
    监控文本
    天干地支纪年法
    Mysql基础
    JDBC基础
  • 原文地址:https://www.cnblogs.com/canglongdao/p/13423732.html
Copyright © 2011-2022 走看看