天天看点

decorator的用法及原理

0、 概念

什么叫装饰器,其实也可以叫做包装器。即对于一个既有的函数func(args),在调用它之前和之后,我们希望都做一些事情,把这个函数包装起来。

python中的装饰器分为两类:函数装饰器和类装饰器。

这里我们先讨论函数装饰器。

1.不带参数的decorator

(1) 基本用法:

  1. def decorator1(func):  
  2.     def dec(*args):  
  3.         print 'pre action'  
  4.         result = func(*args)  
  5.         print 'post action'  
  6.         return result  
  7.     return dec  
  8. @decorator1  
  9. def test_f1(name):  
  10.     print name  
  11.     return None  
  12. test_f1('name1') #out: preaction/name1/post action  
  13. test_f1('name2') #out: preaction/name2/post action  

(2)这种现象的内部原理:

在python内部,当你做了这件事情:

  1. @decorator1  
  2. def test_f1(name):  

其实就是 test_f1 = decorator1(test_f1)#即test_f1作为参数传递给func。

此后的test_f1是装饰器中的dec函数对象了,而不是原来的函数的名称。当调用test_f1(‘name1’)的时候,其实调用的是dec(‘name1’)函数,而在dec函数内部,又调用了func,这样就造成了装饰器的效果。

这也解释了func是被装饰函数,*arg是被装饰函数的参数—这种现象了。

2.带参数的decorator

(1) 基本用法:

  1. def wap(name):  
  2.     def decorator1(func):  
  3.         def dec(*args):  
  4.             print name  
  5.             print 'pre action'  
  6.             result = func(*args)  
  7.             print 'post action'  
  8.             return result  
  9.         return dec  
  10.     return decorator1  
  11. @wap('f1')  
  12. def test_f1(name):  
  13.     print name  
  14.     return None  
  15. @wap('f2')  
  16. def test_f2(name):  
  17.     print name  
  18.     return None  
  19. test_f1('name1') #out: f1/pre action/name1/post action  
  20. test_f1('name2') #out: f2/pre action/name2/post action  

带参数的decorator,作用是通过传递参数可以定制不同的装饰器。

(2) 内部原理

这里和上面 不带参数的decorator类似,

  1. @wap('f1')  
  2. def test_f1(name):  

内部逻辑为: test_f1 =wap(‘f1’)(test_f1)

这里wap(‘f1’)返回是decorator1函数对象,这样的话,wap(‘f1’)(test_f1)其实就是decorator1(test_f1),这样就和上面的一样了。只不过这里传递了一个参数’f1’进入decorator内部,使得我们可以操作这个参数。

3.函数decorator也可以修饰类成员函数

  1. class FOO:  
  2.     @decorator1  
  3.     def fun(self):  
  4.         print self.name  

注意此时fun的self会被传递到decorator1中。此时把self看做普通的函数入参。

4.函数decorator的叠加

(1) 用法

  1. def decorator1(func):  
  2.     def dec(*args):  
  3.         print 'd1 pre'  
  4.         result = func(*args)  
  5.         print 'd1 post'  
  6.         return result  
  7.     return dec  
  8. def decorator2(func):  
  9.     def dec(*args):  
  10.         print 'd2 pre'  
  11.         result = func(*args)  
  12.         print 'd2 post'  
  13.         return result  
  14.     return dec  
  15. @decorator1  
  16. @decorator2  
  17. def test(name):  
  18.     print name  
  19. test('test') #out: d1 pre/d2 pre/test/d1 post/d2 post  

(2) 原理

  1. @decorator1  
  2. @decorator2  
  3. def test(name):  
  4.     print name  

和上面的类似,内部原理是: