装饰器标记一个方法执行不超过一次,即使被多次调用

Posted

技术标签:

【中文标题】装饰器标记一个方法执行不超过一次,即使被多次调用【英文标题】:Decorator to mark a method to be executed no more than once even if called several times 【发布时间】:2010-11-08 12:13:45 【问题描述】:

我直接上例子:

class Foo:
  @execonce
  def initialize(self):
    print 'Called'

>>> f1 = Foo()
>>> f1.initialize()
Called
>>> f1.initialize()
>>> f2 = Foo()
>>> f2.initialize()
Called
>>> f2.initialize()
>>> 

我尝试定义execonce,但无法编写与方法一起使用的定义。

PS:我无法在__init__ 中定义代码,因为initialize 必须在对象初始化之后的某个时间调用。 cf - cmdln issue 13

【问题讨论】:

横向评论:我建议你不要忽略第二个电话。相反,您应该引发异常。如果调用者正在初始化两次,则说明发生了错误,您应该报告它而不是默默地忽略它。当然,我不知道你的具体问题。 Stefano,我同意 .. 这对我来说也很奇怪。基本上,测试用例依次调用这些子命令方法(例如:'svn commit'):command.do_commitcommand.do_update。而且这些子命令中的每一个都必须调用initialize 方法(参见cmdln issue 13)。我不想引发异常......为什么调用者(测试用例)需要了解这样的内部细节? 【参考方案1】:
import functools

def execonce(f):

    @functools.wraps(f)
    def donothing(*a, **k):
        pass

    @functools.wraps(f)
    def doit(self, *a, **k):
        try:
            return f(self, *a, **k)
        finally:
            setattr(self, f.__name__, donothing)

    return doit

【讨论】:

我收到TypeError: donothing() takes at least 1 argument (0 given) 好的,通过从 donothing 方法中删除 self 参数......我能够完成这项工作。 我建议将 functools.wraps 装饰器添加到 doit 和 donthing 中。这样,函数的文档和其他属性将是相同的。 @srid,哎呀,编辑删除自我。 @Manuel,是的,让我也编辑一下……【参考方案2】:

你可以这样做:

class Foo:
  def __init__(self):
    self.initialize_called = False
  def initialize(self):
    if self.initalize_called:
        return
    self.initialize_called = True
    print 'Called'

这是简单易读的。 __init__ 函数中需要另一个实例变量和一些代码,但它会满足您的要求。

【讨论】:

我想避免对我的代码中的每个类都这样做......并且为了 DRY 原则的利益而更喜欢装饰器或其他东西。【参考方案3】:

尝试类似的方法

def foo():
     try:
             foo.called
     except:
             print "called"
             foo.called = True

方法和函数是对象。您可以在它们上添加方法和属性。这对您的情况很有用。如果你想要一个装饰器,只需让装饰器分配方法,但首先,检查标志。如果找到该标志,则返回一个 null 方法并随后执行。

【讨论】:

这可能不起作用,因为方法(在其上调用装饰器)尚未绑定到对象.. 并且initialize 将被调用一次为每个对象 .. 不是所有的对象。

以上是关于装饰器标记一个方法执行不超过一次,即使被多次调用的主要内容,如果未能解决你的问题,请参考以下文章

python -- 装饰器

RxJava 作为事件总线被多次调用,即使只触发一次

为啥装饰器有用? [关闭]

修改冷却装饰器以适用于方法而不是函数

python9-类的装饰器(property, classmethod, staticmethod)

Python进阶精华-编写装饰器为被包装的函数添加参数