【问题标题】:How can I decorate an instance of a callable class?如何装饰可调用类的实例?
【发布时间】:2014-07-30 02:54:32
【问题描述】:
def decorator(fn):
    def wrapper(*args, **kwargs):
        print 'With sour cream and chives!',
        return fn(*args, **kwargs)
    return wrapper

class Potato(object):
    def __call__(self):
        print 'Potato @ {} called'.format(id(self))

spud = Potato()
fancy_spud = decorator(Potato())

通过这段代码,我们有两个可调用类的实例,一个是装饰的,一个是普通的:

>>> spud()
Potato @ 140408136280592 called
>>> fancy_spud()
With sour cream and chives! Potato @ 140408134310864 called

我想知道是否支持在一个可调用的实例上使用@decorator 语法——而不是装饰类/方法,这将适用于每个实例。根据this 流行的回答,@syntax 只是糖:

function = decorator(function)

但这是否过于简单化了?在我所有半生不熟的尝试中,它似乎只有在语法出现在defclass、空格或@another_decorator之前才有效。

@decorator
baked = Potato()

那是SyntaxError

baked = Potato()
@decorator
baked

还有SyntaxError

@decorator
def baked(_spud=Potato()):
    return _spud()

有效,但丑陋且有点作弊。

【问题讨论】:

    标签: python decorator


    【解决方案1】:

    是的,它过于简单化了。如果我们查看the grammardecorator 只出现在规则decorators 中,它只作为classdeffuncdef 的一部分出现:

    decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
    decorators: decorator+
    decorated: decorators (classdef | funcdef)
    

    language reference says(我认为这是链接答案中重复的内容)是什么

    @f1(arg)
    @f2
    def func(): pass
    

    等价于

    def func(): pass
    func = f1(arg)(f2(func))
    

    对于类定义也是如此。但这并不意味着@decorator 语法可以在任何地方应用。它仅在函数或类定义之前有效。

    顺便说一句,即使是官方文档也不是完全正确的;在调用装饰器时,函数(或类)并未绑定到封闭的命名空间或作用域中,因此给定的语法并不完全等价。

    defclass 语句有一些有趣的地方,我认为这是 @decorator 语法支持的唯一语句的部分原因:它们是 Python 中绑定知道该名称是什么的对象

    最后,这是另一种调用装饰器的方法,您可能会喜欢:

    @decorator
    class baked:
        __metaclass__ = lambda *_: Potato()
    

    【讨论】:

      【解决方案2】:

      你的问题是:

      根据这个流行的答案,@syntax 只是糖:

      function = decorator(function)

      不过这样说更准确

      @decorator
      def function():
          pass
      

      是语法糖:

      def function():
          pass
      function = decorator(function)
      

      装饰器专门用于装饰函数、方法或类定义PEP that introduced class decorators 描述了语法:

      decorated: decorators (classdef | funcdef)
      
      funcdef: 'def' NAME parameters ['->' test] ':' suite
      

      如您所见,装饰器必须紧跟在 classdeffuncdef 之前,因此无法直接在可调用类的实例上使用它。

      【讨论】:

        猜你喜欢
        • 2014-12-01
        • 1970-01-01
        • 2019-02-03
        • 2018-04-28
        相关资源
        最近更新 更多