我有一些看起来像这样的课程:
class Foo:
bar = None
@baz(frob=bar)
def oof():
pass
class Rab(Foo):
bar = 'zab'
我无法控制@baz
装饰器,我需要使用新类bar
的类属性Rab
。但是调用Rab.oof()
会使用基类的bar=None
。
答案 0 :(得分:5)
所以这里有一种奇怪/有趣的方法,你只需要修改Foo
,这里的想法是创建一个新的装饰器,延迟baz
装饰直到首次调用该函数使用基于类名的一些缓存,以便它只发生一次。
请注意,这还包括baz
的虚拟实现,它只打印提供的frob
参数,但这种方法应该可以正常工作而无需修改baz
:
def baz(frob):
def deco(func):
def wrapped(*args, **kwargs):
print('frob:', frob)
return func(*args, **kwargs)
return wrapped
return deco
def newdeco(func):
def wrapped(self, *args, **kwargs):
if not hasattr(wrapped, 'cache'):
wrapped.cache = {}
cls = self.__class__.__name__
if cls not in wrapped.cache:
wrapped.cache[cls] = baz(frob=getattr(self.__class__, 'bar'))(func)
wrapped.cache[cls](self, *args, **kwargs)
return wrapped
class Foo:
bar = None
@newdeco
def oof(self):
pass
class Rab(Foo):
bar = 'zab'
f = Foo()
f.oof()
r = Rab()
r.oof()
我还必须根据self
是一种方法的假设向oof
添加oof
参数,如果baz
也将函数转换为静态方法I& #39;我不确定这种方法是否有效。
答案 1 :(得分:3)
你可以从Foo
解包闭包并拉出包装的函数,然后将它重新包装在派生类的装饰器中。但是,如果有任何方法可以让Foo
甚至baz
更改其实施方式,那就更好了。
class Rab(Foo):
bar = 'zab'
oof = baz(frob=bar)(Foo.oof.func_closure[0].cell_contents)
答案 2 :(得分:2)
您可以保留未修饰版本的oof
,让我们将其称为_oof_raw
,并将其重新包装在子类定义中。为了保留未修饰的版本,你需要“手动”装饰,即不使用@
句法糖。
class Foo:
bar = None
def _oof_raw(self):
pass
oof = baz(frob=bar)(_oof_raw)
class Rab(Foo):
bar = 'zab'
oof = baz(frob=bar)(Foo._oof_raw)