Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在类实例方法装饰器上使用类属性?_Python - Fatal编程技术网

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

Python 如何在类实例方法装饰器上使用类属性?,python,Python,我有一些类似这样的课程: class Foo: bar = None @baz(frob=bar) def oof(): pass class Rab(Foo): bar = 'zab' 我无法控制@baz装饰器,我需要使用新类Rab的class属性bar。但是调用Rab.oof()会使用基类的bar=None。您可以从Foo中打开闭包并取出包装的函数,然后在派生类的decorator中重新包装它。但是,如果有任何方法可以通过Foo甚至baz

我有一些类似这样的课程:

class Foo:
    bar = None

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

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

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

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

您可以保留未修饰版本的
oof
,我们称之为
\u oof\u 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)

这里有一种奇怪的/有趣的方法,您只需要修改
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()

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

问题是
@baz(frob=bar)
Foo
的定义下进行评估,而不是重新评估子类化。你能在
Rab
中重载
oof
吗?嗯,那肯定行,但我不想那样做。我确实可以控制
Foo
。您将如何更改该实现以使其更好?您甚至可以将其与元类混合,在元类
\uuuuu new\uuuuu
中进行包装,而不是显式地在每个子类中进行包装。但这仍然是有限的,因为它无法在运行时响应对
Rab.bar
的更改,而不与类变量的访问器进行一些非常重要的磨合。@SilasRay,是的,我同意如果这必须应用于许多子类,那么使用元类可能是一种很好的方法。(但如果不是,我个人的偏好是避免不必要的魔法)这是相当整洁的。您可能希望将
包装。缓存
作为一个
weakkeydirectionary
,并按类对象缓存,而不仅仅是名称(名称可能冲突)。非常好。在这个问题上,这几乎可以肯定是最好的想法这是一个很好的答案,我打算使用檐口资源
@view
装饰器在金字塔应用程序上使用它。我不确定它是否适用于此,因为当应用程序启动时,视图会在Pyramid的配置中注册,但我会尝试并让您知道。谢谢如果它最终不起作用,我就会想到,您可能可以通过
Foo
上的元类做一些聪明的事情来应用decorator。