【问题标题】: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)。我不想引发异常......为什么调用者(测试用例)需要了解这样的内部细节?

标签: python class methods decorator


【解决方案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 将被调用一次为每个对象 .. 不是所有的对象。
猜你喜欢
  • 1970-01-01
  • 2021-09-10
  • 2023-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-22
相关资源
最近更新 更多