I\'m trying to convert the data from a simple object graph into a dictionary. I don\'t need type information or methods and I don\'t need to be able to convert it back to an
In Python there are many ways of making objects behave slightly differently, like metaclasses and whatnot, and it can override getattr and thereby have "magical" attributes you can't see through dict, etc. In short, it's unlikely that you are going to get a 100% complete picture in the generic case with whatever method you use.
Therefore, the answer is: If it works for you in the use case you have now, then the code is correct. ;-)
To make somewhat more generic code you could do something like this:
import types
def todict(obj):
# Functions, methods and None have no further info of interest.
if obj is None or isinstance(subobj, (types.FunctionType, types.MethodType))
return obj
try: # If it's an iterable, return all the contents
return [todict(x) for x in iter(obj)]
except TypeError:
pass
try: # If it's a dictionary, recurse over it:
result = {}
for key in obj:
result[key] = todict(obj)
return result
except TypeError:
pass
# It's neither a list nor a dict, so it's a normal object.
# Get everything from dir and __dict__. That should be most things we can get hold of.
attrs = set(dir(obj))
try:
attrs.update(obj.__dict__.keys())
except AttributeError:
pass
result = {}
for attr in attrs:
result[attr] = todict(getattr(obj, attr, None))
return result
Something like that. That code is untested, though. This still doesn't cover the case when you override getattr, and I'm sure there are many more cases that it doens't cover and may not be coverable. :)
A little update to Shabbyrobe's answer to make it work for namedtuple
s:
def obj2dict(obj, classkey=None):
if isinstance(obj, dict):
data = {}
for (k, v) in obj.items():
data[k] = obj2dict(v, classkey)
return data
elif hasattr(obj, "_asdict"):
return obj2dict(obj._asdict())
elif hasattr(obj, "_ast"):
return obj2dict(obj._ast())
elif hasattr(obj, "__iter__"):
return [obj2dict(v, classkey) for v in obj]
elif hasattr(obj, "__dict__"):
data = dict([(key, obj2dict(value, classkey))
for key, value in obj.__dict__.iteritems()
if not callable(value) and not key.startswith('_')])
if classkey is not None and hasattr(obj, "__class__"):
data[classkey] = obj.__class__.__name__
return data
else:
return obj
One line of code to convert an object to JSON recursively.
import json
def get_json(obj):
return json.loads(
json.dumps(obj, default=lambda o: getattr(o, '__dict__', str(o)))
)
obj = SomeClass()
print("Json = ", get_json(obj))