53

I have a class where I want to get the object back as a dictionary, so I implemented this in the __dict__(). Is this correct?

I figured once I did that, I could then use the dict (custom object), and get back the object as a dictionary, but that does not work.

Should you override __dict__()? How can you make it so a custom object can be converted to a dictionary using dict()?

3 Answers 3

56

No. __dict__ is a method used for introspection - it returns object attributes. What you want is a brand new method, call it as_dict, for example - that's the convention. The thing to understand here is that dict objects don't need to be necessarily created with dict constructor.

Sign up to request clarification or add additional context in comments.

2 Comments

I prefer this answer over the most voted. It's nice to know how dict works, but overriding __iter__ to obtain a dict from an object looks a little hacky to me. It may also have some unintended ramifications.
I wouldn’t call __dict__ a method for introspection. It is a descriptor on the class and it’s use goes well beyond introspection; e.g. giving you direct write access to the attribute namespace of an instance in your code when you have overriden __setattr__ for example.
51

__dict__ is not a special method on Python objects. It is used for the attribute dictionary; dict() never uses it.

Instead, you could support iteration; when dict() is passed an iterable that produces key-value pairs, a new dictionary object with those key-value pairs is produced.

You can provide an iterable by implementing a __iter__ method, which should return an iterator. Implementing that method as a generator function suffices:

class Foo(object): def __init__(self, *values): self.some_sequence = values def __iter__(self): for key in self.some_sequence: yield (key, 'Value for {}'.format(key)) 

Demo:

>>> class Foo(object): ... def __init__(self, *values): ... self.some_sequence = values ... def __iter__(self): ... for key in self.some_sequence: ... yield (key, 'Value for {}'.format(key)) ... >>> f = Foo('bar', 'baz', 'eggs', 'ham') >>> dict(f) {'baz': 'Value for baz', 'eggs': 'Value for eggs', 'bar': 'Value for bar', 'ham': 'Value for ham'} 

You could also subclass dict, or implement the Mapping abstract class, and dict() would recognize either and copy keys and values over to a new dictionary object. This is a little more work, but may be worth it if you want your custom class to act like a mapping everywhere else too.

4 Comments

seems logical, so if you wanted to pass a select set of information back for iter could you use a return {"var1":"val1", ..."varn" : "valn"} instead of yield?
@josh1234: No, __iter__ must return an iterator; a dictionary is not itself an iterator.
@josh1234: and you'd need to produce a sequence of key-value pairs. So iter(somedictionary.items()) is fine, but not somedictionary directly.
@josh1234: the other alternatives are to subclass dict or to otherwise implement the Mapping abstract type.
8

The following method will allow an object of the class to be casted to a dict:

def __iter__(self): for key in self.__dict__: yield key, getattr(self, key) 

1 Comment

This answer was the clearest for me. In my case I supplied a list of keys rather than relying on self.__dict__

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.