Python多重继承类中的类变量

3

我有一个Base类,其中包含一些基本的方法、属性等内容,我还有一个Mixin,我希望能在Base的一个或多个子类中共享它。像这样:

class Base(object): pass

class Mixin(object):
    # IMPORTANT: cache _x locally on Mixin to only compute for all subclasses
    _x = None

    @property
    def x(self):
        if self._x is None:
            print 'reset _x'
            self._x = 2
        return self._x

class A(Base, Mixin): pass
class B(Base, Mixin): pass

重要的是,我希望在Mixin上缓存_x变量,以便在所有子类AB等中只计算一次——计算这个值需要很长时间。奇怪的是,在Python中,这似乎并不像我预期的那样工作:

a = A()
b = B()
print 'calling a.x'
a.x
print 'calling a.x'
a.x
print 'calling b.x'
b.x
print 'calling b.x'
b.x

这将打印出reset _x两次--一次是对a.x的第一次调用,这是我预期的,再一次是对b.x的第一次调用,这是我没有预料到的。我理解Python类属性是按类别一次存储的。有人能解释一下这里发生了什么吗?
在Mixin上本地缓存_x是否有更好的模式?
1个回答

5
您的问题在于引用了self._x。这是一个实例属性,即对于每个实例都不同。如果您没有设置self._x,那么Python会使用继承层次结构中类上找到的第一个_x(这将是Mixin类上的_x),但是一旦您设置了self._x,那么_x将始终在该实例上找到。在新实例上,该属性未设置,因此将使用Mixin._x,但它始终为None,因为您从未更改它。
因此,您希望在所有引用self._x的地方使用Mixin._x,但尤其是在设置该属性时。

跟进这个问题 - 你可以在类范围内进行计算和调用。只需在“声明”_x的地方正确进行计算即可。 - Marcin
你可以这样做,但是这将会在类定义时进行耗时的计算(即在导入包含该类的模块时),这可能会出乎意料。尤其是如果使用该模块的人从未实际使用混合类... - kindall
没错。但是硬编码类的名称并不是最优的选择。将该类变量的值设置为延迟/承诺是可能的。 - Marcin
1
你可以使用 type(self) 来获取类。如果你对它进行子类化,那么你将在子类上设置属性,当然,这可能是你想要的。 - kindall

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接