zoukankan      html  css  js  c++  java
  • python闭包与装饰器

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

    闭包(wrapper)

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

    例如:

    >>>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
    

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

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

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

    装饰器

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

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

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

     多个decorator使用:

    @decorator1                                 #func=decorator2(decorator1(func))
    @decorator2                                 #func=decorator1(func)
    def func():
         pass
    

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

    >>> 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的高阶函数

    >>> 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
    >>> 
    
    >>> now.__name__                           #函数的name属性,通过decorator装饰器调用执行之后返回wrapper函数,所以函数名由func变成了wrapper
    'wrapper'
    

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

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

    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
    

    以上的例子都是从网上找的,比较容易理解的例子。

  • 相关阅读:
    Intent
    What should we do next in general after collecting relevant data
    NOTE FOR Secure Friend Discovery in Mobile Social Networks
    missing pcap.h
    after building Android Source code
    plot point(one column)
    When talking to someone else, don't infer that is has been talked with others at first. It may bring repulsion to the person who is talking with you.
    进程基本知识
    Python input和raw_input的区别
    强制 code review:reviewboard+svn 的方案
  • 原文地址:https://www.cnblogs.com/evablogs/p/6697219.html
Copyright © 2011-2022 走看看