转:python 的函数装饰器Function decorator)

python 的函数装饰器Function decorator)

 

对一个方法应用多个装饰方法:

@A
@B
@C
def f ():
    
#等价于下面的形式,Python会按照应用次序依次调用装饰方法(最近的先调用)
def f():
f
= A(B(C(f)))

 

装饰方法解析:

每个decorator只是一个方法, 可以是自定义的或者内置的(如内置的@staticmethod/@classmethod)。decorator方法把要装饰的方法作为输入参数,在函数体内可以进行任意的操作(可以想象其中蕴含的威力强大,会有很多应用场景), 只要确保最后返回一个可执行的函数即可(可以是原来的输入参数函数, 或者是一个新函数)。decorator的作用对象可以是模块级的方法或者类方法。decorator根据应用时的参数个数不同分为两类:无参数 decorator,有参数decorator。下面分别介绍。

无参数decorator:

def deco(func):
    
"""无参数调用decorator声明时必须有一个参数,这个参数将接收要装饰的方法"""
    
print"Enter decorator"     #进行额外操作
     func.attr ='decorated'     #对函数进行操作,增加一个函数属性
    return func   #返回一个可调用对象(此例还是返回作为输入参数的方法)
                      #返回一个新函数时,新函数可以是一个全局方法或者decorator函数的内嵌函数,
                      #只要函数的签名和被装饰的函数相同

@deco
def MyFunc():   #应用@deco修饰的方法
    print"Enter MyFunc"

MyFunc()     
#调用被装饰的函数

注意:当使用上述方法定义一个decorator方法时,函数体内的额外操作只在被装饰的函数首次调用时执行,如果要保证额外操作在每次调用被装饰的函数时都执行,需要换成如下的写法:

def deco(func):
    
def replaceFunc():     #定义一个内嵌函数,此函数包装了被装饰的函数,并提供额外操作的代码
        print"Enter decorator"     #进行额外操作
        return func()    #产生对被装饰函数的调用
    return replaceFunc   #由于返回的是这个新的内嵌函数,所以确保额外操作每次调用得以运行

@deco
def MyFunc():   #应用@deco修饰的方法
    print"Enter MyFunc"

MyFunc()     
#调用被装饰的函数

 

 

有参数decorator:

def decoWithArgs(arg):
    
"""由于有参数的decorator函数在调用时只会使用应用时的参数而不接收被装饰的函数做为参数,
        所以必须返回一个decorator函数, 由它对被装饰的函数进行封装处理
"""
    
def newDeco(func):    #定义一个新的decorator函数
        def replaceFunc():    #在decorator函数里面再定义一个内嵌函数,由它封装具体的操作
            print"Enter decorator"     #进行额外操作
            return func()    #对被装饰函数进行调用
        return replaceFunc
    
return newDeco    #返回一个新的decorator函数

@decoWithArgs(
"demo")
def MyFunc():    #应用@decoWithArgs修饰的方法
    print"Enter MyFunc"
    
MyFunc()    
#调用被装饰的函数

 

当我们对某个方法应用了装饰方法后, 其实就改变了被装饰函数名称所引用的函数代码块入口点,使其重新指向了由装饰方法所返回的函数入口点。由此我们可以用decorator改变某个原有函数的功能,添加各种操作,或者完全改变原有实现。

例子 11.2 使用函数装饰器的例子(deco.py)

这个装饰器(以及闭包)示范表明装饰器仅仅是用来“装饰“ (或者修饰)函数的包装,返回一
个修改后的函数对象,将其重新赋值原来的标识符,并永久失去对原始函数对象的访问。

1 #!/usr/bin/env python
2
3 from time import ctime, sleep
4
5 def tsfunc(func):
6 def wrappedFunc():
7   print '[%s] %s() called' % (
8   ctime(), func.__name__)
9   return func()
10 return wrappedFunc
11
12 @tsfunc
13 def foo():
14 pass
15
16 foo()
17 sleep(4)
18
19 for i in range(2):
20 sleep(1)
21 foo()

运行脚本,我们得到如下输出:

[Sun Mar 19 22:50:28 2006] foo() called
[Sun Mar 19 22:50:33 2006] foo() called
[Sun Mar 19 22:50:34 2006] foo() called

参考:
http://www.cnblogs.com/jifangliang/archive/2008/07/22/1248313.html
http://www.x5dj.com/Blog/00182202/00574182.shtml
http://hi.baidu.com/cricstiano/blog/item/83f9ce732dad7f1b8701b0f3.html
posted @ 2011-12-07 22:32  babykick  阅读(598)  评论(0编辑  收藏  举报