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}
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'
However, there probably is a lot of code around that makes other assumptions about the __dict__
attribute on instances that might make using the above in production code more problematic than it’s worth.