1、什么是装饰器?
装饰器(Decorator)相对简单,咱们先介绍它:“装饰器的功能是将被装饰的函数当作参数传递给与装饰器对应的函数(名称相同的函数),并返回包装后的被装饰的函数”,听起来有点绕,没关系,直接看示意图,其中 a 为与装饰器 @a 对应的函数, b 为装饰器修饰的函数,装饰器@a的作用是:
简而言之:@a 就是将 b 传递给 a(),并返回新的 b = a(b)!!!
举例:
#! /usr/bin/env python
#coding=utf-8
def dec(arg): #与装饰器对应的函数
return arg() #(1)注意不是arg
@dec #装饰器
def func(): #被装饰的函数
print('decorator')
if __name__ == '__main__':
func #(2)注意不是func()!!!
上面使用@dec来表示装饰器,其等同于:func = dec(func)
因此装饰器本质上就是个语法糖,其作用为简化代码,以提高代码可读性
解释过程:
(1)python 解释器发现@dec,就去调用与其对应的函数( dec 函数)
(2)dec函数调用前要指定一个参数,传入的就是@dec下面修饰的函数,也就是 func()
(3)dec() 函数执行,调用 func(),func() 打印“decorator”
另一种形式:
#! /usr/bin/env python
#coding=utf-8
def dec(arg): #与装饰器对应的函数
return arg #(1)注意
@dec #装饰器
def func(): #被装饰的函数
print('decorator')
if __name__ == '__main__':
func() #(2)注意
结果都是:
decorator
2、什么是闭包?
在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。
上面提到了两个关键的地方: 自由变量 和 函数, 这两个关键稍后再说。还是得在赘述下“闭包”的意思,望文知意,可以形象的把它理解为一个封闭的包裹,这个包裹就是一个函数,当然还有函数内部对应的逻辑,包裹里面的东西就是自由变量,自由变量可以在随着包裹到处游荡。当然还得有个前提,这个包裹是被创建出来的。
在通过Python的语言介绍一下,一个闭包就是你调用了一个函数A,这个函数A返回了一个函数B给你。这个返回的函数B就叫做闭包。你在调用函数A的时候传递的参数就是自由变量。!!!
例如:
#! /usr/bin/env python
#coding=utf-8
def func(name):
def inner_func(age):
print 'name:', name, 'age:', age
return inner_func
if __name__ == '__main__':
bb = func('the5fire')
bb(26) # >>> name: the5fire age: 26
结果:
name: the5fire age: 26
这里面调用func的时候就产生了一个闭包:inner_func,并且该闭包持有自由变量name,因此这也意味着,当函数func的生命周期结束之后,name这个变量依然存在,因为它被闭包引用了,所以不会被回收。!!!
3、闭包与装饰器
上面已经简单演示了装饰器的功能,事实上,装饰器就是一种的闭包的应用,只不过其传递的是函数。
#! /usr/bin/env python
#coding=utf-8
def deco(func):
def _deco():
print 'before invoked'
func()
print 'after invoked'
return _deco
@deco
def f():
print 'f is invoked'
if __name__ == '__main__':
f()
在f上加deco装饰器相当于f = deco(f), 和functools.partial有些类似
如果被装饰的函数f带参数且有返回值:
#! /usr/bin/env python
#coding=utf-8
def deco(func):
def _deco(*args, **kwargs):
print 'before invoked'
ret = func(*args, **kwargs)
print 'after invoded'
return ret
return _deco
@deco
def f(a):
print 'f is invoked'
return a + 1
if __name__ == '__main__':
f(1)
print '#'*15
res = f(1)
print res
结果:
before invoked
f is invoked
after invoded
###############
before invoked
f is invoked
after invoded
2