【发布时间】:2011-03-23 05:59:36
【问题描述】:
是否有一种简洁的方法让装饰器仅在实例化类的实例时调用类的实例方法?
class C:
def instance_method(self):
print('Method called')
def decorator(f):
print('Locals in decorator %s ' % locals())
def wrap(f):
print('Locals in wrapper %s' % locals())
self.instance_method()
return f
return wrap
@decorator
def function(self):
pass
c = C()
c.function()
我知道这不起作用,因为 self 在调用 decorator 时未定义(因为它没有作为实例方法调用,因为没有对该类的可用引用)。然后我想出了这个解决方案:
class C:
def instance_method(self):
print('Method called')
def decorator():
print('Locals in decorator %s ' % locals())
def wrap(f):
def wrapped_f(*args):
print('Locals in wrapper %s' % locals())
args[0].instance_method()
return f
return wrapped_f
return wrap
@decorator()
def function(self):
pass
c = C()
c.function()
这使用了这样一个事实,即我知道任何实例方法的第一个参数都是self。这个包装器定义方式的问题是每次执行函数时都会调用实例方法,这是我不想要的。然后我想出了以下有效的细微修改:
class C:
def instance_method(self):
print('Method called')
def decorator(called=[]):
print('Locals in decorator %s ' % locals())
def wrap(f):
def wrapped_f(*args):
print('Locals in wrapper %s' % locals())
if f.__name__ not in called:
called.append(f.__name__)
args[0].instance_method()
return f
return wrapped_f
return wrap
@decorator()
def function(self):
pass
c = C()
c.function()
c.function()
现在该函数只被调用一次,但我不喜欢每次调用该函数时都必须进行此检查的事实。我猜没有办法解决它,但如果有人有任何建议,我很想听听他们的意见!谢谢:)
【问题讨论】:
-
如果您使用 (AFAIK) python 2.5+,您可能应该子类化对象:
class C(object):以获得新型类的好处。 -
你的名字错了。你所说的
decorator实际上是一个装饰器factory,你所说的wrap是装饰器。此外,使用called=[]具有一定的欺骗性;即使在这种情况下它是正确的。 -
@katriealex 够公平的。我最近才熟悉装饰器的这种语法。我在另一个代码库中有这个示例,所以我只是快速重命名了这些函数以进行清理。感谢您的澄清:)
标签: python methods decorator instance