在Python中,当装饰程序大大简化任务时,有哪些示例?
试着找出装饰师什么时候真的有用,什么时候没那么有用的例子。在Python中,当装饰程序大大简化任务时,有哪些示例?,python,decorator,Python,Decorator,试着找出装饰师什么时候真的有用,什么时候没那么有用的例子。 欢迎使用示例代码。通常的示例是使用@property装饰器创建只读属性: @property def count(self): return self._events 而不是: def _get_count(self): return self._events count = property(_get_count) class Bar(object): def foo(cls): retu
欢迎使用示例代码。通常的示例是使用
@property
装饰器创建只读属性:
@property
def count(self):
return self._events
而不是:
def _get_count(self):
return self._events
count = property(_get_count)
class Bar(object):
def foo(cls):
return id(cls)
foo = classmethod(foo)
在AppEngine API中,有一个很好的decorator,它可以清理大量代码:
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
、只读属性的@property
。在函数之前有装饰器比在函数之后有装饰器更好,就像在
class Bar(object):
@classmethod
def foo(cls):
return id(cls)
而不是:
def _get_count(self):
return self._events
count = property(_get_count)
class Bar(object):
def foo(cls):
return id(cls)
foo = classmethod(foo)
它只保存样板代码。装饰器是调用高阶函数的特定方法的简单语法,因此如果您只关注语法,则不太可能产生巨大的差异。瞧,不管你说什么
@mydecorator
def f(...):
# body of f
你可以同样地说
def f(...):
# body of f
f = mydecorator(f)
decorator语法的优点是它稍微简洁一点(不重复f
三次;-),并且它位于def
(或class
,对于类decorators)语句之前,因此可以立即提醒代码的读者。这很重要,但它不可能是伟大的
decorator的语义(同样,如果没有decorator,则匹配此模式的高阶函数调用的语义;-)。比如说,
@classmethod
def f(cls, ...):
允许您创建类方法(特别是对于备用构造函数非常有用),以及
允许您创建只读属性(2.6中的其他相关修饰符用于非只读属性;-),即使未使用也非常有用(因为它们可以避免编写大量愚蠢的“样板文件”)本质上是属性的访问器…只是因为访问属性可能需要在将来触发一些计算!-)
除了Python中内置的装饰器之外,您自己的装饰器也同样重要——当然,这取决于您的应用程序是什么。一般来说,它们可以很容易地将代码的某些部分(否则必须在许多函数和类中进行复制[[或者对于类的情况,您可能不得不求助于元类,但这些元类更丰富、更复杂,以便正确使用]])重构到装饰器中。因此,它们可以帮助您避免重复的样板代码,因为“不要重复自己”是软件开发的一个核心原则,因此,您应该衷心欢迎在这方面获得的任何帮助。了解装饰程序的有用性的最简单方法是看一些示例。举个例子: 假设您正在学习一些代码并希望 了解何时以及如何调用函数。 您可以使用装饰器来更改函数 因此,每次调用函数时,它都会打印一些调试信息:
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))
但是如果您有许多想要跟踪的函数,或者
不想弄乱原来的代码,那就装潢吧
变得有用
有关其他有用的decorator示例,请参阅。decorator用于合并两个概念的设计选择,如“日志记录”和“库存管理”或“已注册用户”和“查看最新消息”
- 其中一个概念是包装另一个概念,控制如何调用它。这个概念就是装饰
- 第二个概念与第一个概念永久地结合在一起,如此之多以至于失去它是可以接受的 直接调用第二个概念的能力。例如,失去调用“查看最新消息”而不调用“已注册用户”的功能
- 日志记录。这可能与事务处理器结合起来,以记录每个成功或失败的事件 交易失败
- 需要安全。这可能与库存价格的变化相结合
- 缓存(或记忆)。这可能与净现值计算或任何昂贵的静态只读操作相结合
- 语言修复,如“@classmethod”或“将错误返回值转换为异常”
- 向框架注册,例如“当按钮被激活时调用此函数” 按
- 状态机处理,其中装饰器决定下一步处理哪个状态
- 等等等等
您可以查看(已过期的wiki页面)或dectools()库以获取更多文档和示例。代码契约使生活更轻松-可以通过装饰器完成。您的文档字符串可能应该应用于
跟踪
,您可以在那里查找它,而不是包装
,在那里它无论如何都会被包装
破坏。