在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用于合并两个概念的设计选择,如“日志记录”和“库存管理”或“已注册用户”和“查看最新消息”

  • 其中一个概念是包装另一个概念,控制如何调用它。这个概念就是装饰
  • 第二个概念与第一个概念永久地结合在一起,如此之多以至于失去它是可以接受的 直接调用第二个概念的能力。例如,失去调用“查看最新消息”而不调用“已注册用户”的功能
当设计选择正确时,decorator语法(或decorator的语法糖) 清晰阅读,消除误解中的错误

通常的装饰器概念包括:

  • 日志记录。这可能与事务处理器结合起来,以记录每个成功或失败的事件 交易失败
  • 需要安全。这可能与库存价格的变化相结合
  • 缓存(或记忆)。这可能与净现值计算或任何昂贵的静态只读操作相结合
  • 语言修复,如“@classmethod”或“将错误返回值转换为异常”
  • 向框架注册,例如“当按钮被激活时调用此函数” 按
  • 状态机处理,其中装饰器决定下一步处理哪个状态
  • 等等等等

您可以查看(已过期的wiki页面)或dectools()库以获取更多文档和示例。

代码契约使生活更轻松-可以通过装饰器完成。您的文档字符串可能应该应用于跟踪,您可以在那里查找它,而不是包装,在那里它无论如何都会被包装破坏。