[转载]Python Decorator

Decorate是装饰的意思。如果你了解Decorator设计模式,那么就很好理解Python的Decorator。

 

http://en.wikipedia.org/wiki/Python_syntax_and_semantics#Decorators

Decorator是一个可调用的python object。Decorator可以用来修改funciton, method 或者类的定义。

一个object被传进decotator,然后decorator修改这个object并且返回这个object,最后,这个返回的object绑定到原来的那个object的名字上。

Decorator是一个语法糖(syntactic sugar)

创造Decorator这个语法糖的灵感来源于Java的annotations

@viking_chorus
def menu_item():
    print("spam")
等价于
def menu_item():
    print ("spam")
menu_item = viking_chorus(menu_item)

对上面代码的一点说明:上面代码很简答, 就是最基本的decotator的功能。viking_chorus是一个decorator,它修饰一个函数,这个函数的名字叫做menu_item。那么与它等价的代码可以描述为:仍然有一个函数名字叫做menu_item,这个函数是一个可调用的python object,所以我们把它传递给decotator(这里就是viking_chorus),viking_chorus里对这个可调用的object进行操作并且返回一个object,最后把这个返回的object命名为menu_item。由此可见,原来的menu_item已经不见了,与这个名字绑定的可调用python object变成了decorator的返回值。

前面说过,Decorator是装饰者模式。下面就是一个例子:

# decorator的定义,它使得对menu_item的一次调用会调用8次原来的menu_item
def viking_chorus(myfunc):
    def inner_func(*args, **kwargs):
        for i in range(8):
            myfunc(*args, **kwargs)
    return inner_func

对上面代码的一点说明:viking_chorus是一个decorator,如前所说,它接受一个被修饰的callable python object,返回一个python object。这里传进来的python object就是myfunc(它是decorator的参数),返回的python object就是函数内部定义的inner_func。而inner_func调用了传进来的myfunc。这样就达到了修饰被修饰python objectg的目的。不过需要注意的是对原来的python object修饰以后其实是返回了另外一个python object作为修饰的结果。

Decoratr最典型的应用是创建class method或者叫做static method(类似于C++的静态函数),增加function attributes,tracing,设置pre和postcondition以及synchronisation。除此以外, decorator还可以用在很多地方比如tail recursion elimination,memoization甚至improving the writing of decorators.

多个Decorator用在一起可以形成一个修饰链比如:

@invincible
@favorite_color("Blue")
def black_knight():
    pass
等价于
def black_knight():
    pass
invincible(favorite_color("Blue")(black_knight()))

对上面代码的一点说明:favorite_color是一个函数,它接受一个字符串作为一个参数。这个函数应该返回一个Decorator,这个返回的Decorator被用来修饰black_night,修饰的结果是一个callable python object,这个callable python objecti接着又被invincible修饰。

下面的代码更加清楚的说明这个过程:

def black_knight():
    pass
blue_decorator = favorite_color("Blue")
decorated_by_blue = blue_decorator(black_knight)
black_knight = invincible(decorated_by_blue)
#注意上面一行,返回值必须被赋给black_knight,
# 这样下次你调用black_knight函数的时候才会调用那个被层层修饰过的函数

那么那个favorite_color如何实现呢,前面已经说过了,它是一个函数,它返回一个decorator,我们把这个叫做一个工厂(factory),如下面的代码:

def favorite_color(color):
    def decorator(func):
        def wrapper():
            print(color)
            func()
        return wrapper
    return decorator

前面说python的decorator和decorator设计模式有点相似,但是还是要区分,decorator设计模式是一种针对静态类型面向对象编程语言的设计模式,该设计模式允许在运行时增加对象的功能。而python的decorator是一种语法糖,是在函数或者类定义的时候使用的。


Python26之前,只有函数可以应用decorator,如果想对类应用可以针对__init__函数使用decorator。
Python26开始,有了类的decorator。

http://blog.genforma.com/2011/07/28/class-decorator-talk/

使用class decorator,你可以检查类的属性,绑定其他操作比如logging,transaction等等。

与class decorator使用一个类作为参数,并且返回一个类。decorator的原理是一样的,作为参数的类被修饰,并且返回一个新的类,新的类被赋予参数类的名字,这样当你再用该名字访问这个类的时候,你就得到被修饰过的那个新的类。

比如下面的decorator为你增加一个类的静态变量

def add_foo_decorator(cls):
    cls.foo = "foo"
    return cls

使用上面的class decorator:

@add_foo_decorator
class A:
    pass
#注意,这个时候你就可以访问A.foo了。

同样的,class decorator也是语法糖,你可以这样实现同样的功能:

class A:
    pass
A = add_foo_decorator(A)

同样的,class decorator也可以形成一个链,同样的,你也可以用一个接受参数的函数返回一个class decorator并且用这个decorator来修饰类

@cls_decorator
@cls_decorator_factory("parameter", 2)
class B:
    pass

实现上面代码中的cls_decorator_factory和实现一个类似的修饰函数的decorator是类似的,这里就不多说了。

 

原文:http://www.cnblogs.com/dbbs/archive/2012/03/07/2382918.html

posted @ 2012-08-25 23:45  semiok  阅读(232)  评论(0编辑  收藏  举报