If I run this code, I'v got the subject error message. But why? And how to avoid it getting the C
class having its parents slots?
class A():
__slots__ = ['slot1']
class B():
__slots__ = ['slot2']
class C(A, B):
__slots__ = []
Simply speak, you just cannot do it.
As stated in Documentation,
Multiple inheritance with multiple slotted parent classes can be used, but only one parent is allowed to have attributes created by slots (the other bases must have empty slot layouts) - violations raise TypeError.
The idea behind __slots__
is to reserve specific slots for each attribute in the memory layout of your instances. A
and B
are trying to reserve the same part of their memory layout for the slot1
and slot2
attributes, and C
can't have the same memory reserved for two attributes. It's just not compatible.
Thanks for JCode metioned in comment, the following method is modified to be correct.
But there is always the way, I personally prefer to use a common base contained all required slots if __slots__
is necessary while there is multiple inherited class.
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))
Update
The 4 values will be 88, 88, 88, 312. Though __slots__
reserved.
It had (in my opinion) a silly workaround.
That's why no TypeError
is raised when __slots__
is empty, and having an empty __slots__
attribute preserves the "wondered" python behaviour what warns when assigning to an attribute not defined in __slots__
.
So, consider the following metaclass:
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)
An then deploy on base classes.
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'
If we execute following code
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'
This produces following output
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'
来源:https://stackoverflow.com/questions/53060607/python-3-6-5-multiple-bases-have-instance-lay-out-conflict-when-multi-inherita