• python闭包与装饰器


    https://www.cnblogs.com/evablogs/p/6697219.html

    有关闭包和装饰器的知识点的理解着实花了我不少时间,整理笔记更是无从下手,但还是将从网上搜索学习的点滴记录下来以便后期的一个补充学习。

    闭包(wrapper)

    闭包通俗地解释就是通过调用了函数A,函数A返回了函数B,返回的函数B就是所谓的闭包,在调用函数A的时候传递的参数就是自由变量,该自由变量是被函数A引用的,在函数A的生命周期结束后仍然存在,这句话是至今能让我比较能理解的解释。

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    >>>def func1(name):                             #定义一个函数func1
               def func2(age):                      #函数func2()是在func1调用的时候产生的一个闭包,且引用了自由变量name
                     print name,age
               return func2                         #函数调用完毕返回函数func2
     
    >>> a=func1('Lily')                             #调用函数func1,且传递参数‘Lily’,将结果赋给a
    >>> a(24)                                       #上一步的结果是返回函数func2,这时再将参数24赋给函数func1,调用函数func2
    Lily 24

    闭包不能修改外部作用域的局部变量:

    1
    2
    3
    4
    5
    6
    7
    8
    >>> def a():
        x=1                                 #局部变量x的值为1
        def b():
            x=0                         #在闭包内对x的值进行重新赋值
        return x
     
    >>> a()
    1                                           #结果是x的值没有改变

    使用闭包的好处呢一个就是在闭包运行之后,保存当前的运行环境,另一个是通过外部作用域的变量可以返回不同的值。

    装饰器

    装饰器是闭包的使用场景之一,装饰器其实也就是闭包的应用,只是区别的是装饰器传递的参数是函数。装饰器是将函数作为参数传递给一个函数,并对其进行加工处理即装饰返回一个新的函数,装饰器能保证在不改变已有的函数的结构,调用该函数返回一个新的函数,极大地提高了效率。

    使用标识符@将装饰器应用在函数上,只需要在函数的定义前加上@和装饰器的名称,即@decorator

    1
    2
    3
    @decorator                                  #解释器将会解释成:func=decorator(func),即将函数func作为参数传递给函数decorator,然后再返回新的函数赋值给func
    def func():
          pass

     多个decorator使用:

    1
    2
    3
    4
    @decorator1                                 #func=decorator2(decorator1(func))
    @decorator2                                 #func=decorator1(func)
    def func():
         pass

     再来一个打印调用函数前log日志的无参数的装饰器例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    >>> def log(f):
         def wrapper(*args):
               print 'call %s()' %(f.__name__)
               return f(*args)
         return wrapper
     
    >>> @log
    def func():
         print 'hello,world'
     
          
    >>> func()
    call func()
    hello,world

     带参数的装饰器:

    带参数的装饰器比不带参数的装饰器还要复杂一点,需要编写一个返回decorator的高阶函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    >>> def log(text):                                                   #3层嵌套的函数
        def decorator(f):                                            #返回decorator函数
            def wrapper(*args):
                print '%s %s()' %(text,f.__name__)           #将log的参数excute传递过来赋给text
                return f(*args)
            return wrapper
        return decorator                                            #先执行log('excute')函数,返回decorator函数,再调用返回wrapper函数,最后返回一个新的func函数
    >>> @log('excute')
    def func():
         print 'hello,world'
     
          
    >>> func()
    excute func()
    hello,world
    >>>
    1
    2
    >>> now.__name__                           #函数的name属性,通过decorator装饰器调用执行之后返回wrapper函数,所以函数名由func变成了wrapper
    'wrapper'

    所以,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。

    不需要编写wrapper.__name__ = f.__name__这样的代码,Python内置的functools.wraps就是干这个事的,所以,一个完整的decorator的写法如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import functools
     
    def log(text):
        def decorator(f):
            @functools.wraps(f)
            def wrapper(*args, **kw):
                print('%s %s():' % (text, f.__name__))
                return f(*args, **kw)
            return wrapper
        return decorator
  • 相关阅读:
    [转]SDRAM中的一些疑惑点
    [转]如何学习小波分析?
    [转]功率谱和频谱的区别、联系
    使用Vim为每一行自动编号
    [转]阿英 Matlab fftshift 详解
    [转]性噪比和相位失真
    神舟笔记本精盾K480N高频噪声消除方法
    Tips:verilog计数分频计算
    vim的列编辑操作
    【题解】 「CTSC2018」暴力写挂 点分治+虚树+树形dp LOJ2553
  • 原文地址:https://www.cnblogs.com/yuer20180726/p/10790358.html
Copyright © 2020-2023  润新知