【问题标题】:Can a method be a decorator of another method of the same class?一个方法可以是同一个类的另一个方法的装饰器吗?
【发布时间】:2012-07-29 06:00:00
【问题描述】:

我有一个类在他们的函数上有一个乏味的重复模式,我想把这个模式变成一个装饰器。但问题是这个装饰器必须访问当前实例的一些属性,所以我想把它变成这个类中的一个方法。我有一些问题。

所以,这与我想要的相似:

class DullRepetitiveClass:
    def __init__(self, nicevariable):
        self.nicevariable = nicevariable

    def mydecorator(self, myfunction):
        def call(*args, **kwargs):
            print "Hi! The value of nicevariable is %s"%(self.nicevariable,)
            return myfunction(*args, **kwargs)
        return call

    @mydecorator            #Here, comment (1) below.
    def somemethod(self, x):
        return x + 1

(1) 这就是问题所在。我想用DullRepetitiveClass.mydecorator方法来装饰somemethod方法。但是我不知道如何使用当前实例中的方法作为装饰器。

有简单的方法吗?

编辑:好的,答案很明显。正如 Sven 在下面所说,装饰器本身只是转换方法。方法本身应该处理与实例有关的所有事情:

def mydecorator(method):
    def call(self, *args, **kwargs):
        print "Hi! The value of nicevariable is %s"%(self.nicevariable,)
        return method(self, *args, **kwargs)
    return call


class DullRepetitiveClass:
    def __init__(self, nicevariable):
        self.nicevariable = nicevariable

    @mydecorator            
    def somemethod(self, x):
        return x + 1

【问题讨论】:

  • 请修正缩进。另请注意,您的代码不包含任何类方法。
  • 您是在问如何将self 以外的不同 实例传递给mydecorator,因为它装饰了somemethod
  • 糟糕。从 vim 复制并粘贴到浏览器有时会很痛苦......
  • 虽然不访问实例,但使用可调用类作为装饰器可以在调用之间将状态保存在类中。这不会回答这个问题,但可能会导致某人出于其他目的遇到此问题。

标签: python instance decorator


【解决方案1】:

装饰器只有一个参数——它所装饰的函数或方法。它没有作为self 参数传递一个实例——在调用装饰器的那一刻,甚至还没有创建类,更不用说类的实例了。该实例将作为第一个参数传递给修饰函数,因此您应该将self 作为第一个参数包含在call() 的参数列表中。

我认为没有必要在类范围内包含装饰器。你可以这样做,但你也可以在模块范围内使用它。

【讨论】:

  • 如果你的装饰器需要使用类成员怎么办?或者这只是一个坏主意/模式?
  • @weirdcanada:由于在调用装饰器时该类尚未创建,因此您无法以普通方式访问其成员。您可以做一些技巧来解决这个问题(例如将 locals() 作为参数传递给装饰器),但它们并不明显,我想不出这样做的充分理由。
  • 我有一个这样的例子。让我找到它。
  • 好的,我有一个名为 maxima@property 和另一个名为 minima。但是,当它们被调用时,我需要检查它们是否被计算过。我没有编写两次该逻辑,而是编写了一个基本上以if self.new_values is None 开头的包装器,然后相应地计算maximaminima,完成后将self.new_values 设置为False。一开始我有点不舒服,因为我定义了def new_values_for_extrema_validator(method),然后将其中的包装器定义为def wrapper(self, *args, **kwargs)。因此,它在内部引用了 self。
  • @weirdcanada:你所做的正是我在回答中建议的。您只能访问 wrapper 函数内的 instance 成员,这很好。我的最后一条评论是关于访问 decorator 函数中的 class 成员,这是完全不同的。 (我也会对你的要点写一个小评论。)
猜你喜欢
  • 2021-10-23
  • 1970-01-01
  • 2021-12-26
  • 2015-12-08
  • 1970-01-01
  • 2011-07-03
  • 2020-10-15
  • 1970-01-01
  • 2021-04-20
相关资源
最近更新 更多