Recursively convert python object graph to dictionary

前端 未结 9 1556
既然无缘
既然无缘 2020-12-04 10:25

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

相关标签:
9条回答
  • 2020-12-04 10:58

    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. :)

    0 讨论(0)
  • 2020-12-04 11:01

    A little update to Shabbyrobe's answer to make it work for namedtuples:

    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
    
    0 讨论(0)
  • 2020-12-04 11:05

    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))
    
    0 讨论(0)
提交回复
热议问题