If classes provide __slots__
and at the same time inherit from another class also providing __slots__
, there is no straightforward way to access and list each and every slot of the class. Especially when you consider chaining of inheritance.
I've written this meta-class that adds the __all_slots__
property, listing all unique slots:
class MetaSlotMachine(type):
"""Meta-class that adds the attribute `__all_slots__` to a class.
`__all_slots__` is a set that contains all unique slots of a class,
including the ones that are inherited from parents.
"""
def __init__(cls, name, bases, dictionary):
super(MetaSlotMachine, cls).__init__(name, bases, dictionary)
slots_iterator = (getattr(c, '__slots__', ()) for c in cls.__mro__)
# `__slots__` might only be a single string,
# so we need to put the strings into a tuple.
# `basestring` becomes just `str` in Python 3
slots_converted = ((slots,) if isinstance(slots, basestring) else slots
for slots in slots_iterator)
cls.__all_slots__ = set()
cls.__all_slots__.update(*slots_converted)
Let's consider classes that inherit slots, like the following:
class HasSlots1(object):
__metaclass__ = MetaSlotMachine # Python 2 Syntax
__slots__ = ['x', 'y']
class HasSlots2(HasSlots1):
__slots__ = 'zz'
class HasSlots3(HasSlots2):
__slots__ = ()
If we create and instance via
myslots = HasSlots3()
and ask for
myslots.__slots__
Python will return the empty tuple:
()
However, now we can get hold of all slots via
myslots.__all_slots__
which returns all inherited slots:
{'y', 'x', 'zz'}
Is there anything flawed with the design of the meta-class? What about listing all slots based on the __mro__
in _get_all_slots
function?
EDIT: Revised version with gathering slots within the init function. Moreover, special care is taken about __slots__
that only consist of a single string, like __slots__ = '__weakref__'
.