Cannot inherit from multiple classes defining __slots__?
class, python, slots
Solution
By forcing a constraint that no class defines __slots__, a special object class could be constructed with the characteristics desired for all child classes. The class is registered as an alias for regular objects.
class _object: __slots__ = '_MetaSafe__exec', '__dict__'
class MetaSafe(type):
__REGISTRY = {object: _object}
@classmethod
def clone(cls, old):
return cls(old.__name__, old.__bases__, dict(old.__dict__), old)
def __new__(cls, name, bases, classdict, old=None):
# Check on a few classdict keys.
assert '__new__' not in classdict, '__new__ must not be defined!'
assert '__slots__' not in classdict, '__slots__ must not be defined!'
assert '__module__' in classdict, '__module__ must be defined!'
# Validate all the parent classes.
valid = []
for base in bases:
if base in cls.__REGISTRY:
valid.append(cls.__REGISTRY[base])
elif base in cls.__REGISTRY.values():
valid.append(base)
else:
valid.append(cls.clone(base))
# Wrap callables without thread mark.
for key, value in classdict.items():
if callable(value):
classdict[key] = cls.__wrap(value)
# Fix classdict and create new class.
classdict.update({'__new__': cls.__new, '__slots__': (), '__module__':
'{}.{}'.format(__name__, classdict['__module__'])})
cls.__REGISTRY[old] = new = \
super().__new__(cls, name, tuple(valid), classdict)
return new
def __init__(self, name, bases, classdict, old=None):
return super().__init__(name, bases, classdict)
@staticmethod
def __wrap(func):
@functools.wraps(func)
def safe(self, *args, **kwargs):
return self.__exec(func, self, *args, **kwargs)
return safe
@classmethod
def __new(meta, cls, *args, **kwargs):
self = object.__new__(cls, *args, **kwargs)
if 'master' in kwargs:
self.__exec = kwargs['master'].__exec
else:
array = tuple(meta.__REGISTRY.values())
for value in args:
if isinstance(value, array):
self.__exec = value.__exec
break
else:
self.__exec = Affinity()
return self
This code can be used as a building block to make `tkinter` thread-safe by cloning its classes. The `Affinity` class automatically ensures that code is executed on a single thread, preventing GUI errors.
Problem
A certain situation in Python recently alarmed me, and its reason is still not completely clear after a little research. The following class definitions appear to work flawlessly and will produce what is intended: ``` class A: __slots__ = 'a', 'b' class B(A): __slots__ = () class C(A): __slots__ = () class D(B, C): __slots__ = () ``` These are four classes arranged in a diamond inheritance pattern. However, a somewhat similar pattern is not allowed. The following class definitions seem as though they should function the same as the first: ``` class B: __slots__ = 'a', 'b' class C: __slots__ = 'a', 'b' class D(B, C): __slots__ = () Traceback (most recent call last): File "<pyshell#74>", line 1, in <module> class D(B, C): __slots__ = () TypeError: multiple bases have instance lay-out conflict ``` However, a `TypeError` is raised in this example. So three questions arise: (1) Is this a bug in Python, considering the slot names? (2) What would justify such an answer? (3) What is the best workaround? References: - __slots__ and multiple inheritance (with replies following) - Multiple inheritance and __slots__ - Don't use __slots__ - Multiple Inheritance __slots__ problem