python的装饰器之我解

本质上来说, 就是闭包加python的一个语法糖.
亲们,让我们从头说起:

python中一切皆对象,方法也是一个对象.
def foo():
      print 'this is func foo'

isinstance(foo, object)
True

所以TA可以被作为方法的形参传进去, 也可以作为return value被return.
我们先记下这一点, 后面会详细说明.

内嵌方法(nested function):

python允许在方法内部定义一个方法, 内部方法可以引用操作外部方法的变量.

def outer():
    para = 1
    print 'this is outer func'
    def inner():
        print 'this is inner func'
        print 'outer para in inner is %s' % para
        return para
    return inner()

 print outer()
 print para 

输出如下:

  this is outer func
  this is inner func
  outer para in inner is 1
  1
  NameError: name 'para' is not defined

一个方法内部变量的生命周期, 应该是在执行这个方法时被define, 方法执行完毕后被delete. 在这个例子里print outer()之后, para必定不能再被使用, 如果再加一个print para, 必定会报错. okay, 目前为止, 一切都是按我们预想的来, 看起来也很好理解.

闭包(closures)

我们把上面的例子稍微改一改:

  def outer(): 
        para = 1 
        print 'this is outer func' 
        def inner(): 
                print 'this is inner func' 
                print 'outer para in inner is %s' % para
                return para
        return inner

  closure = outer()

输出如下:

this is outer func

这次我们把outer()的返回值改成inner这个方法本身。是不是看起来有点怪怪的?前面已经提到,方法在python里本身也是一个对象,so, why not?
从输出可以看出,调用outer()之后,inner方法并没有被执行。这也是好理解的。在python中,“()”是调用操作符,既然outer返回的是inner而不是inner(),说明inner就没有被call,所以它没有执行。cool,到这里虽然看起来有些复杂,但还是在比较好理解的范围之内。
我们继续:

 print closure()

输出:

 this is inner func
 outer para in inner is 1
 1

这个是不是就有点难理解了?outer方法已经被执行完了,那么para的生命周期已经结束,inner怎么还可以用它?不报错?
** 这就是python对闭包的支持。**
如果我们dir一个方法(dir(closure)),会看到有func_closure这么一个内置的属性。如果此方法是一个闭包,那就会把闭包里用到的对象塞到这个属性里。

print closure.func_closure

输出:

(,)

这个int对象就是我们例子里可爱的para.

装饰器(decorator):

升级一下上个例子, 给outer改个名字,同时传个参数。

 def decor(func):
        print 'this is func decor'
        def inner():
                  print 'this is inner func'
                  print 'call func in inner.'
                  func()
        return inner

 def foo():
          print 'this is func foo'

 foo = decor(foo)
 foo()

输出:

this is func decor
this is inner func
call func in inner.
this is func foo

改名之后的方法叫decor,加了个参数func。把decor(foo)重新赋值给foo, 并执行foo。
结果是原有的foo被执行,还有我们的inner。是不是很酷,相当于给foo加了个包装(wrapper)。
我们离胜利仅剩一步!
@这个符号是python对闭包采用的一个语法糖(syntax suger)。

 def decor(func):
        print 'this is func decor'
        def inner():
                  print 'this is inner func'
                  print 'call func in inner.'
                  func()
        return inner
 @decor
 def foo():
          print 'this is func foo'

 # foo = decor(foo)
 foo()

一样的输出:

this is func decor
this is inner func
call func in inner.
this is func foo

用了@语法糖,就相当于去掉了foo = decor(foo)这一步,让代码看起来更优雅,更readable。
That's it。这就是装饰器。
如需转载, 请注明出处!谢谢

还可以用class来做装饰器,请参考:class decorator
也可以给装饰器传参数,请参考:decorator with arguments

你可能感兴趣的:(python的装饰器之我解)