How can I convert python class with slots to dictionary?

python, python-2.7

Solution

Use the `__slots__` attribute plus `getattr()` in a dictionary comprehension:

{
    s: getattr(obj, s)
    for s in {
        s
        for cls in type(obj).__mro__
        for s in getattr(cls, '__slots__', ())
    }
    if hasattr(obj, s)
}

which collects the slot names from all base classes and skips any attributes not set.

Alternative, setting missing attributes to `None`:

{
    s: getattr(obj, s, None)
    for s in {
        s
        for cls in type(obj).__mro__
        for s in getattr(cls, '__slots__', ())
    }
}

Demo:

>>> class Foo(object):
...     __slots__ = ('bar', 'spam')
... 
>>> obj = Foo()
>>> obj.bar = 42
>>> {s: getattr(obj, s) for s in {s for cls in type(obj).__mro__ for s in getattr(cls, '__slots__', ())} if hasattr(obj, s)}
{'bar': 42}
>>> {s: getattr(obj, s, None) for s in {s for cls in type(obj).__mro__ for s in getattr(cls, '__slots__', ())}}
{'spam': None, 'bar': 42}

You can even make that a property of the class and `vars()` will make use of it:

>>> class Foo(object):
...     __slots__ = ('bar', 'spam')
...     @property
...     def __dict__(self):
...         return {
...             s: getattr(self, s)
...             for s in {
...                 s
...                 for cls in type(self).__mro__
...                 for s in getattr(cls, '__slots__', ())
...             }
...             if hasattr(self, s)
...         }
... 
>>> f = Foo()
>>> f.bar = 42
>>> f.__dict__
{'bar': 42}
>>> f.spam = 'eggs'
>>> f.__dict__
{'spam': 'eggs', 'bar': 42}
>>> vars(f)
{'spam': 'eggs', 'bar': 42}
>>> f.hello = 'world'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'hello'

Problem

I am using class with slots to reduce the memory which the instance will occupy. Now, how can I convert a slot instance to dictionary ? The slot class look like this : ``` class Foo(object): __slots__ = ['x','y','z'] def __init__(self): self.x = 1 self.y = 2 self.z = 3 ``` I expect something like this: ``` y = Foo() y.__dict__ {'x': 1, 'y': 2, 'z': 3} ```

Original source