装饰器标记一个方法执行不超过一次,即使被多次调用
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_commit
和command.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
将被调用一次为每个对象 .. 不是所有的对象。以上是关于装饰器标记一个方法执行不超过一次,即使被多次调用的主要内容,如果未能解决你的问题,请参考以下文章