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

Dan*_* P. 8 python

我有一些看起来像这样的类:

class Foo:
    bar = None

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

class Rab(Foo):
    bar = 'zab'
Run Code Online (Sandbox Code Playgroud)

我无法控制@baz装饰器,我需要使用bar新类的class属性Rab.但是调用Rab.oof()使用bar=None基类.

And*_*ark 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()
Run Code Online (Sandbox Code Playgroud)

我还必须添加一个self参数,oof基于假设oof是一个方法,如果baz还将函数转换为静态方法,我不确定这种方法是否有效.


Sil*_*Ray 3

可以打开闭包Foo并取出包装的函数,然后将其重新包装在派生类的装饰器中。但如果有什么方法可以实现Foo甚至baz改变它们的实现,那就更好了。

class Rab(Foo):
    bar = 'zab'
    oof = baz(frob=bar)(Foo.oof.func_closure[0].cell_contents)
Run Code Online (Sandbox Code Playgroud)