如何在类实例方法装饰器上使用类属性?

2024-06-15 06:00:44 发布

您现在位置:Python中文网/ 问答频道 /正文

我有些课看起来像这样:

class Foo:
    bar = None

    @baz(frob=bar)
    def oof():
        pass

class Rab(Foo):
    bar = 'zab'

我不能控制@baz修饰符,我需要使用新类Rab的class属性bar。但是调用Rab.oof()使用基类的bar=None。在


Tags: none属性foodefbarpassbaz修饰符
3条回答

您可以Foo展开闭包并拉出包装好的函数,然后在派生类的decorator中重新包装它。但是如果有任何方法可以在Foo或者甚至baz来更改它们的实现,那就更好了。在

class Rab(Foo):
    bar = 'zab'
    oof = baz(frob=bar)(Foo.oof.func_closure[0].cell_contents)

所以这里有一种奇怪的/有趣的方法,你只需要修改Foo,这里的想法是创建一个新的decorator来延迟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()

我还必须在假设oof是一个方法的基础上,向oof添加一个self参数,如果{}也将函数转换为staticmethod,我不确定这种方法是否有效。在

您可以保留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)

相关问题 更多 >