您的位置:首页 > 编程语言 > Python开发

python里的装饰器

2011-10-25 17:25 513 查看
装饰器是一个函数,其主要用途是包装另一个函数或类。这种包装的首要目的是透明地修改或增强包装对象的行为。表示装饰器的语法是特殊符号@,如下所示:

@trace
def square(x):
return x*x


上面的代码可以简化为:

def square(x):
return x*x
square = trace(square)

这个例子中定义了函数square()。但在定义之后,函数对象本身就立即被传递给函数trace(),后者返回一个对象替代原始的square。现在,让我们考虑trace的实现,从而说明这样做的用处:

enable_tracing = True
if enable_tracing:
debug_log = open('debug.log','w')
def trace(func):
if enable_tracing:
def callf(*args, **kwargs):
debug_log.write("Calling %s: %s, %s\n" % (func.__name__, args, kwargs))
r = func(*args, **kwargs)
debug_log.write("%s returned %s\n" % (func.__name__, r))
return r
return callf
else:
return func

在这段代码中,trace()创建了写有一些调试输出的包装器函数。然后调用了原始函数对象。因此如果调用square()函数,看到的将是包装器中write()方法的输出。trace()函数返回的函数callf是一个闭包,用于替换原始的函数。关于这种实现的一个有趣方面是,跟踪功能本身只能像上面这样使用全局变量enable_tracing来启用。如果把这个变量设置为False,trace()装饰器只是返回未修改的原始函数。因此,禁用跟踪时,使用装饰器不会增加性能负担。

使用装饰器时,他们必须出现在函数或类定义之前的单独行上。可以同时使用多个装饰器,例如:

@foo
@bar
@spam
def grok(x):
pass

在这个例子中,装饰器按照他们出现的先后顺序应用,结果是:

def grok(x):
pass
grok = foo(bar(spam(grok)))

装饰器也可以接受参数,例如:

@eventhandler('BUTTON')
def handle_button(msg):
...
@eventhandler('RESET')
def handle_reset(msg):
...

如果提供参数,装饰器的语义如下所示:

def handle_button(msg):
...
temp = eventhandler('BUTTON')        #使用提供的参数调用装饰器
handle_button = temp(handle_button)  #调用装饰器返回的函数

在这个例子中,装饰器函数只接受带有@描述符的参数。它接着返回在调用时使用函数作为参数的函数。下面给出了一个例子:

#事件处理程序装饰器
event_handlers = {}
def eventhandler(event):
def register_function(f):
event_handlers[event] = f
return f
return register_function

装饰器也可以应用于类定义,例如:

@foo
class Bar(object):
def __init__(self, x):
self.x = x
def spam(self):
statements

对于类装饰器,应该让装饰器函数始终返回类对象作为结果。需要使用原始类定义的代码可能要直接引用类成员,如Bar.spam。如果装饰器函数foo()返回一个函数,这种引用就是不正确的

摘自:python参考手册第4版 6.5 节 82页
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: