什么是将嵌套的Python对象转换为字典的最经济实用的方法?

15
我有一些包含多个SQLAlchemy对象列表的SQLAlchemy对象,以此类推(大约5层)。 我希望将所有对象转换为字典。
我可以使用__dict__属性将对象转换为字典,没有问题。 但是,我无法找到将所有嵌套对象转换为字典的最佳方法,而不必明确执行每个级别。
到目前为止,这是我能想到的最好方法,但它不能正确递归。 它基本上在一次传递后就会中断,因此我的逻辑显然出了问题。 你能看出问题出在哪里吗?
我希望能够实现:
all_dict = myDict(obj.__dict__)

def myDict(d):
    for k,v in d.items():
        if isinstance(v,list):
            d[k] = [myDict(i.__dict__) for i in v]
        else:
            d[k] = v
    return d

1
你想让生成的字典模仿相同的嵌套结构,还是想要将其展平? - Tim Pietzcker
1
请注意,使用__dict__属性时,您还将包括来自基类的所有方法和内容。 - Björn Pollex
请查看此答案:https://dev59.com/vHNA5IYBdhLWcg3wQ7Uw#1118038 但要注意它无法处理自引用数据结构。 - Björn Lindqvist
谢谢,很接近但不幸的是我的炼金术对象中有反向引用,因此该方法会循环。 - MFB
@bjorn-lindqvist 请看一下我的代码,我很想知道您的想法。 - MFB
显示剩余2条评论
2个回答

46

生活技巧:

def to_dict(obj):
    return json.loads(json.dumps(obj, default=lambda o: o.__dict__))

使用json.dumps()方法(或json.dump())的default输入,通过返回不可序列化对象的__dict__表示来实现。请注意,当对象包含非标准数据结构(例如NumPy或Pandas)时,这可能无法正常工作。以下是json.dump文档中的描述:

如果指定了,则default应该是一个函数,用于处理无法序列化的对象。它应该返回对象的JSON可编码版本或引发TypeError。如果未指定,则将引发TypeError。


这是一个更加清晰的解决方案,使用 Python 3 可以完成任务。 - Matt Haidet
我喜欢这个!我本来想用递归来实现它,但这种方法非常聪明地简化了问题! - Steven C. Howell
我有一些嵌套的Python dataclass,这个函数解决了我的问题,谢谢! - Emad Goahri

15

我不确定我是否完全理解您想要的内容 - 但如果我理解正确,这个函数可以做到您想要的:

它会在对象属性上进行递归搜索,并产生一个嵌套字典和列表结构,以Python对象作为终点,这些对象没有__dict__属性 - 在SQLAlchemy的情况下,这些对象很可能是基本的Python类型,如数字和字符串。(如果失败,用更明智的替换“hasattr dict”测试应该可以修复代码以满足您的需要。

def my_dict(obj):
    if not  hasattr(obj,"__dict__"):
        return obj
    result = {}
    for key, val in obj.__dict__.items():
        if key.startswith("_"):
            continue
        element = []
        if isinstance(val, list):
            for item in val:
                element.append(my_dict(item))
        else:
            element = my_dict(val)
        result[key] = element
    return result

1
谢谢 jsbueno。它有效了,我只需要修改一下以排除我的数据中的自引用对象即可。 干杯! - MFB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接