You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Python复杂嵌套类转换为字典?有哪些可用工具?

问题描述

我有若干自定义类,其实例包含str、int、float、list、dict等基础类型,同时还嵌套了其他同类型的自定义类,形成多层嵌套对象。这些数据以对象形式方便后续操作,处理完成后我希望将其转换为嵌套字典,从而存储为数据库中的JSON对象。这种需求常见吗?有没有可实现该功能的库?

目前我打算自己实现一个函数来完成转换,但担心递归实现会导致栈溢出。以下是我的代码雏形:

def getObjectAsDict(self):
    d = {}

    for name_of_attr in dir(some_class):
        if name_of_attr.startswith("_"):
            continue

        value_of_attr = getattr(some_class, name_of_attr)

        if isinstance(value_of_attr, str):
            pass
        elif isinstance(value_of_attr, int):
            pass
        elif isinstance(value_of_attr, float):
            pass
        elif isinstance(value_of_attr, bool):
            pass
        elif isinstance(value_of_attr, list):
            for idx, item in enumerate(value_of_attr):
                # some recursion logic here
        elif isinstance(value_of_attr, dict):
            for key, value in value_of_attr.items():
                # some recursion logic here
        elif isinstance(value_of_attr, ComplexObject):
            value_of_attr = value_of_attr.getObjectAsDict()
                # some recursion logic here
        else:
            continue
        d[name_of_attr] = value_of_attr
回答
  • 需求常见性:这种需求非常常见,ORM对象转数据库JSON字段、API接口序列化数据、复杂配置对象持久化等场景里,都经常需要把嵌套自定义对象转成可序列化的字典结构。

  • 可用成熟库:

    • dataclasses.asdict:如果你的类是用Python3.7+的dataclasses装饰器定义的,直接调用dataclasses.asdict()就能自动处理嵌套的dataclass对象,递归逻辑做了常规场景的优化,不用担心普通深度的栈溢出。
    • pydantic:如果需要序列化+数据校验的组合能力,Pydantic模型自带的dict()方法可以完美处理嵌套模型,还支持自定义序列化规则,底层实现对递归深度做了合理限制。
    • attrs:和dataclasses类似,attrs库的asdict()方法也能轻松转换嵌套的attrs类实例为字典,用法简洁。
  • 手动实现优化建议:如果坚持自己写逻辑,你的代码雏形可以做这些优化:

    1. 别用dir(some_class)遍历属性,dir()会返回大量类内置属性和方法,建议直接指定需要序列化的属性列表,或者过滤出实例属性且非方法的项。
    2. 基础类型不需要单独写pass,直接加入字典即可。
    3. 把递归逻辑抽成独立辅助函数,避免重复代码。
    4. 针对极深嵌套场景,改用迭代方式(用栈/队列存储待处理对象),彻底规避栈溢出风险。

优化后的递归版示例:

def obj_to_dict(obj):
    # 直接返回基础类型
    if isinstance(obj, (str, int, float, bool, type(None))):
        return obj
    # 处理列表:递归转换每个元素
    elif isinstance(obj, list):
        return [obj_to_dict(item) for item in obj]
    # 处理字典:递归转换每个值
    elif isinstance(obj, dict):
        return {key: obj_to_dict(value) for key, value in obj.items()}
    # 处理自定义对象:过滤非私有、非方法属性后递归转换
    else:
        result = {}
        for attr_name in dir(obj):
            if attr_name.startswith("_"):
                continue
            attr_value = getattr(obj, attr_name)
            if callable(attr_value):
                continue
            result[attr_name] = obj_to_dict(attr_value)
        return result

# 示例自定义类
class ComplexObject:
    def __init__(self):
        self.name = "demo"
        self.count = 456
        self.child = ComplexObject()  # 嵌套测试

obj = ComplexObject()
print(obj_to_dict(obj))

迭代版(无栈溢出风险)示例:

def obj_to_dict_iterative(obj):
    stack = [(obj, None, {})]
    result = {}
    while stack:
        current_obj, parent_key, parent_container = stack.pop()
        
        # 处理基础类型
        if isinstance(current_obj, (str, int, float, bool, type(None))):
            if parent_key is not None:
                if isinstance(parent_container, list):
                    parent_container[parent_key] = current_obj
                else:
                    parent_container[parent_key] = current_obj
            else:
                result = current_obj
            continue
        
        # 处理列表
        elif isinstance(current_obj, list):
            new_list = []
            if parent_key is not None:
                parent_container[parent_key] = new_list
            else:
                result = new_list
            # 倒序入栈保证处理顺序正确
            for idx, item in enumerate(reversed(current_obj)):
                stack.append((item, idx, new_list))
        
        # 处理字典
        elif isinstance(current_obj, dict):
            new_dict = {}
            if parent_key is not None:
                parent_container[parent_key] = new_dict
            else:
                result = new_dict
            for key, value in reversed(current_obj.items()):
                stack.append((value, key, new_dict))
        
        # 处理自定义对象
        else:
            new_dict = {}
            if parent_key is not None:
                parent_container[parent_key] = new_dict
            else:
                result = new_dict
            # 过滤非私有、非方法属性后倒序入栈
            attrs = [(attr, getattr(current_obj, attr)) for attr in dir(obj) 
                     if not attr.startswith("_") and not callable(getattr(current_obj, attr))]
            for attr_name, attr_value in reversed(attrs):
                stack.append((attr_value, attr_name, new_dict))
    return result

内容的提问来源于stack exchange,提问作者tyleax

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 11:43:18