试图找到装饰器在何时非常有益,何时不太有用的示例代码。
欢迎提供示例代码。
装饰器是一种特定的高阶函数调用的简单语法,因此,如果你只关注语法,它不太可能产生很大的差异。换句话说,无论何时你可以这样说:
@mydecorator
def f(...):
# body of f
你可以同样地说
def f(...):
# body of f
f = mydecorator(f)
f
),并且它出现在def
(或者对于类装饰器来说,是class
)语句之前,从而立即提醒代码的读者。这很重要,但只是不能太棒了!@classmethod
def f(cls, ...):
让您创建类方法(特别适用于替代构造函数),并
@property
def foo(self, ...):
让您可以创建只读属性(2.6中的其他相关装饰器用于非只读属性;-),即使不使用它们,它们也非常有用(因为它们可以避免您为本质上是属性的内容编写很多愚蠢的“样板”访问器...仅仅因为对属性的访问可能需要在将来触发一些计算!-)。
除了Python内置的装饰器外,您自己的装饰器可能同样重要--当然这取决于您的应用程序是什么。通常,它们使得将代码的某个部分重构到装饰器中变得容易(否则该部分代码必须在许多函数和类中进行复制[[或者你可能不得不使用元类来处理类的情况,但那些更丰富且更复杂,使用不正确会导致问题]])。因此,它们帮助您避免重复的、样板式的代码--由于DRY,“不要重复自己”,是软件开发的核心原则,任何帮助您实现该原则的工具都应该受到热烈的欢迎。
@property
def count(self):
return self._events
替代:
def _get_count(self):
return self._events
count = property(_get_count)
理解装饰器的最简单方法是看一些例子。例如:
假设你正在研究一些代码并希望了解函数何时以及如何被调用。 你可以使用装饰器来改变函数,使其在每次调用函数时打印一些调试信息:
import functools
def trace(f):
'''This decorator shows how the function was called'''
@functools.wraps(f)
def wrapper(*arg,**kw):
arg_str=','.join(['%r'%a for a in arg]+['%s=%s'%(key,kw[key]) for key in kw])
print "%s(%s)" % (f.__name__, arg_str)
return f(*arg, **kw)
return wrapper
@trace
def foo(*args):
pass
for n in range(3):
foo(n)
打印:
# foo(0)
# foo(1)
# foo(2)
如果您只希望跟踪一个名为foo
的函数,您当然可以将代码更简单地添加到foo
的定义中:
def foo(*args):
print('foo({0})'.format(args))
但如果您有许多希望跟踪的函数,或者不想干扰原始代码,则装饰器变得非常有用。
有关其他有用装饰器的示例,请参见装饰器库。
trace
,在那里你可以查找它,而不是应用于 wrapper
,因为它会被 wraps
销毁。 - Mike Graham@login_required
装饰器,可以大大简化代码:class MyPage(webapp.RequestHandler):
@login_required
def get(self):
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write("Hello, world!")
相反:
class MyPage(webapp.RequestHandler):
def get(self):
user = users.get_current_user()
if not user:
return self.redirect(users.create_login_url(self.request.uri))
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write("Hello, world!")
@classmethod
、静态方法的 @staticmethod
,以及(如Mike DeSimone所说)只读属性的 @property
。将装饰器放在函数前面比后面更容易阅读,就像这样:class Bar(object):
@classmethod
def foo(cls):
return id(cls)
改为:
class Bar(object):
def foo(cls):
return id(cls)
foo = classmethod(foo)
它只是节省样板代码。
装饰器用于设计选择,其中您正在合并两个概念,例如“日志记录”和“库存管理”或“已注册用户”和“查看最新消息”。
当设计选择正确时,装饰器语法(或用于装饰器的语法糖)读起来清晰,并消除了由于误解而产生的错误。
通常的装饰器概念包括:
您可以查看http://wiki.python.org/moin/PythonDecoratorLibrary(已过时的维基页面)或dectools(http://pypi.python.org/pypi/dectools)库以获取更多文档和示例。