Py学习  »  Python

python 3.6.5当多个继承具有槽的类时,“多个基具有实例布局冲突”__

xsubira • 7 年前 • 1972 次点击  

如果我运行此代码,我将收到主题错误消息。但是为什么呢?如何避免它 C 班级有家长名额?

class A():
        __slots__ = ['slot1']

class B():
        __slots__ = ['slot2']

class C(A, B):
        __slots__ = []
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/40391
文章 [ 2 ]  |  最新文章 7 年前
xsubira
Reply   •   1 楼
xsubira    8 年前

在我看来,这是一个愚蠢的变通办法。 所以才没有 TypeError 当 __slots__ 是空的,有一个空的 斯洛茨基 属性保留“奇怪的”python行为当分配给未在 斯洛茨基 .

所以,考虑一下 元类 :

class SlotBase(type):
    def __new__(cls,name,bases,dctn):
        if ('_slots_' in dctn) and not ('__slots__' in dctn):
            dctn['__slots__'] = []
        elif '__slots__' in dctn:
            for base in bases:
                if hasattr(base,'_slots_'):
                    dctn['__slots__'] += getattr(base,'_slots_')
        return super().__new__(cls,name,bases,dctn)

然后在基类上部署。

class A(metaclass=SlotBase):

    _slots_=['slot1'] #fake __slots__ attribute

    classPropertyA = 'Some silly value'

    def functA(self):
        print('I\'m functA')

class B(metaclass=SlotBase):

    _slots_=['slot2'] #fake __slots__ attribute

    classPropertyB = 'Some other silly value'

    def functB(self):
        print('I\'m functB')

class C(A,B):
    __slots__ = []

    classPropertyC = 'Just another silly value'

如果我们执行以下代码

c=C()
c.classPropertyC
c.classPropertyA
c.functA()
c.functB()
c.slot1='Slot exists then assignment is accepted'
c.slot3='Slot does not exists then assignment couldn\'t be accepted'

这将产生以下输出

Just another silly value
Some silly value
I'm functA
I'm functB
Traceback (most recent call last):
  File "/tmp/slots.py", line 41, in <module>
    c.slot3='Slot does not exists then assignment couldn\'t be accepted'
AttributeError: 'C' object has no attribute 'slot3'
user2357112
Reply   •   2 楼
user2357112    7 年前

简单地说,你就是做不到。

如上所述 Documentation ,

可以使用具有多个时隙父类的多重继承,但仅允许一个父类具有由时隙创建的属性(其他基必须具有空的时隙布局)-冲突会引发类型错误。

背后的想法 __slots__ 是为了保留特定的 槽 对于实例的内存布局中的每个属性。 A 和 B 正在尝试为 slot1 和 slot2 属性,以及 C 不能为两个属性保留相同的内存。只是不兼容。


感谢注释中的jcode,下面的方法被修改为正确的。

但总有一种方法,我个人更喜欢使用包含所有必需插槽的公共基 斯洛茨基 当存在多个继承类时是必需的。

import pympler.asizeof
class base():
    __slots__ = ['a','b']

class A(base):
    __slots__ = []

class B(base):
    __slots__ = []

class C(A,B):
    __slots__ = []

class D():
    pass

#Update
bb = base()
bb.a = 100
bb.b = 100
print(pympler.asizeof.asizeof(bb))
a = A()
a.a = 100
a.b = 100
print(pympler.asizeof.asizeof(a))
c = C()
c.a = 100
c.b = 100
print(pympler.asizeof.asizeof(c))
d = D()
d.a = 100
d.b = 100
print(pympler.asizeof.asizeof(d))

更新 这4个值是88,88,88,312。虽然 斯洛茨基 保留的。