python装饰器的原理
装饰器的原理就是利用《闭包函数》来实现,闭包函数的原理就是包含内层函数的return和外层环境变量:
装饰器: 装饰器本质上是一个Python函数,其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值(return)也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。
1
2
3
4
5
6
7
8
9
|
先来看一个简单例子: def foo(): print ( 'i am foo' ) 现在有一个新的需求,希望可以记录下函数的执行日志,于是在代码中添加日志代码: def foo(): print ( 'i am foo' ) logging.info( "foo is running" ) |
bar()、bar2()也有类似的需求,怎么做?再写一个logging在bar函数里?这样就造成大量雷同的代码,为了减少重复写代码,我们可以这样做,重新定义一个函数:专门处理日志 ,日志处理完之后再执行真正的业务代码
1
2
3
4
5
6
7
8
|
def use_logging(func): logging.warn( "%s is running" % func.__name__) func() def bar(): print ( 'i am bar' ) use_logging(bar) |
逻 辑上不难理解, 但是这样的话,我们每次都要将一个函数作为参数传递给use_logging函数。而且这种方式已经破坏了原有的代码逻辑结构,之前执行业务逻辑时,执行 运行bar(),但是现在不得不改成use_logging(bar)。那么有没有更好的方式的呢?当然有,答案就是装饰器。
简单装饰器
![](data:image/png;base64,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)
函 数use_logging就是装饰器,它把执行真正业务方法的func包裹在函数里面,看起来像bar被use_logging装饰了。在这个例子中,函 数进入和退出时 ,被称为一个横切面(Aspect),这种编程方式被称为面向切面的编程(Aspect-Oriented Programming)。
@符号是装饰器的语法糖,在定义函数的时候使用,避免再一次赋值操作
如 上所示,这样我们就可以省去bar = use_logging(bar)这一句了,直接调用bar()即可得到想要的结果。如果我们有其他的类似函数,我们可以继续调用装饰器来修饰函数,而不 用重复修改函数或者增加新的封装。这样,我们就提高了程序的可重复利用性,并增加了程序的可读性。
装饰器在Python使用如此方便都要归因于Python的函数能像普通的对象一样能作为参数传递给其他函数,可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内。
带参数的装饰器
装饰器还有更大的灵活性,例如带参数的装饰器:在上面的装饰器调用中,比如 @use_logging,该装饰器唯一的参数就是执行业务的函数。装饰器的语法允许我们在调用时,提供其它参数,比如@decorator(a)。这 样,就为装饰器的编写和使用提供了更大的灵活性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
def use_logging(level): def decorator(func): def wrapper( * args, * * kwargs): if level = = "warn" : logging.warn( "%s is running" % func.__name__) return func( * args) return wrapper return decorator @use_logging (level = "warn" ) def foo(name = 'foo' ): print ( "i am %s" % name) foo() |
上 面的use_logging是允许带参数的装饰器。它实际上是对原有装饰器的一个函数封装,并返回一个装饰器。我们可以将它理解为一个含有参数的闭包。当 我 们使用@use_logging(level="warn")调用的时候,Python能够发现这一层的封装,并把参数传递到装饰器的环境中。
类装饰器
再来看看类装饰器,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器还可以依靠类内部的__call__方法,当使用 @ 形式将装饰器附加到函数上时,就会调用此方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
class Foo( object ): def __init__( self , func): self ._func = func def __call__( self ): print ( 'class decorator runing' ) self ._func() print ( 'class decorator ending' ) @Foo def bar(): print ( 'bar' ) bar() |
使用装饰器极大地复用了代码,但是他有一个缺点就是原函数的元信息不见了,比如函数的docstring、__name__、参数列表,先看例子:
装饰器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
def logged(func): def with_logging( * args, * * kwargs): print func.__name__ + " was called" return func( * args, * * kwargs) return with_logging 函数 @logged def f(x): """does some math""" return x + x * x 该函数完成等价于: def f(x): """does some math""" return x + x * x f = logged(f) 不难发现,函数f被with_logging取代了,当然它的docstring,__name__就是变成了with_logging函数的信息了。 print f.__name__ # prints 'with_logging' print f.__doc__ # prints None |
这个问题就比较严重的,好在我们有functools.wraps,wraps本身也是一个装饰器,它能把原函数的元信息拷贝到装饰器函数中,这使得装饰器函数也有和原函数一样的元信息了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
from functools import wraps def logged(func): @wraps (func) def with_logging( * args, * * kwargs): print func.__name__ + " was called" return func( * args, * * kwargs) return with_logging @logged def f(x): """does some math""" return x + x * x print f.__name__ # prints 'f' print f.__doc__ # prints 'does some math' |
@staticmathod、@classmethod、@property
装饰器的顺序
@a
@b
@c
def f ():
等效于 f = a(b(c(f)))