Generic Pickle-Aware Super-Class for Mixing Classes with and without __slots__ in Python I want a generic super-class that I can easily subclass - and if desired add slots to my class - without having to worry about any pickle issues (with the lowest protocol). Is this in general a good idea? And if so, is this class a good implementation?

class HasSlots(object):
    """Top-class that allows mixing of classes with and without slots.

    Takes care that instances can still be pickled with the lowest
    protocol. Moreover, provides a generic `__dir__` method that
    lists all slots.

    """

    # We want to allow weak references to the objects
    __slots__ = ['__weakref__']  

    def _get_all_slots(self):
        """Returns all slots as set"""
        all_slots = (getattr(cls, '__slots__', []) 
                         for cls in self.__class__.__mro__)
        return set(slot for slots in all_slots for slot in slots)

    def __getstate__(self):
        if hasattr(self, '__dict__'):
            # We don't require that all sub-classes also define slots,
            # so they may provide a dictionary
            statedict = self.__dict__.copy()
        else:
            statedict = {}
        # Get all slots of potential parent classes
        for slot in self._get_all_slots():
            try:
                value = getattr(self, slot)
                statedict[slot] = value
            except AttributeError:
                pass
        # Pop slots that cannot or should not be pickled
        statedict.pop('__dict__', None)
        statedict.pop('__weakref__', None)
        return statedict

    def __setstate__(self, state):
        for key, value in state.items():
            setattr(self, key, value)

    def __dir__(self):
        result = dir(self.__class__)
        result.extend(self._get_all_slots())
        if hasattr(self, '__dict__'):
            result.extend(self.__dict__.keys())
        return result


Thus, I can simply sub-class this without worrying about slots and pickle:

class MyClass(HasSlots):
    def __init__(self, x,y):
        self._x = x
        self._y = y


but later maybe I want to optimize it and simply add some slots:

class MySlotClass(HasSlots):
    __slots__ = ['_x', '_y']
    def __init__(self, x,y):
        self._x = x
        self._y = y


And I still want to guarantee that my new object can be pickled:

import pickle
pickle.loads(pickle.dumps(MyClass(1,2))
pickle.loads(pickle.dumps(MySlotClass(1,2))


Are there any serious issues with my idea and implementation? Is this: all_slots = (getattr(cls, '__slots__', []) for cls in self.__class__.__mro__) a good approach to take care that all slots are properly pickled? 

Is the approach safe for sub-classes that reference each other in a circular fashion?
A few of trivial points:


getattr(cls, '__slots__', []) would be better as getattr(..., ()) - tuples are immutable so are normally cached by the implementation.
set(slot for slots in all_slots for slot in slots) would be better as {slot for slots in all_slots for slot in slots}
It might be better to do

try:
    statedict = vars(self).copy()
except TypeError:
    statedict = {}