以下是为提供的 Python 代码编写的 **Markdown 格式技术文档**,涵盖了功能说明、类与函数的详细描述、使用示例等。 --- # `DictObject` 模块技术文档 本模块提供了一个增强型字典对象 `DictObject`,支持通过属性访问键值(如 `obj.key`),并可递归封装嵌套数据结构。同时提供了 JSON 序列化支持和多值字典转单值/列表字典的工具函数。 ## 目录 - [核心功能概述](#核心功能概述) - [函数 `multiDict2Dict`](#function-multidict2dictmd) - [类 `DictObjectEncoder`](#class-dictobjectencoderjsonencoder) - [类 `DictObject`](#class-dictobjectdict) - [方法概览](#方法概览) - [详细方法说明](#详细方法说明) - [辅助静态方法 `_wrap` 和 `_dict`](#辅助静态方法-_wrap-和-_dict) - [已注释工厂函数 `dictObjectFactory`](#已注释掉的工厂函数-dictobjectfactory建议扩展用) - [使用示例](#使用示例) - [注意事项与限制](#注意事项与限制) --- ## 核心功能概述 该模块主要实现以下功能: 1. **属性式访问字典**:允许像操作对象属性一样读写字典内容。 2. **自动类型包装**:对嵌套的字典或列表自动转换为 `DictObject` 或其列表形式。 3. **安全访问机制**:访问不存在的属性返回 `None` 而非抛出异常。 4. **JSON 可序列化支持**:通过自定义编码器支持复杂对象的 JSON 输出。 5. **多值字典合并工具**:将多个同名键的值合并为列表。 --- ## Function: `multiDict2Dict(md)` 将一个多值字典(如 Web 表单中常见的多个同名参数)转换为标准字典,若某键有多个值,则将其合并为一个列表。 ### 参数 | 参数 | 类型 | 说明 | |------|------|------| | `md` | `dict` 或 `MultiDict` | 输入的多值字典 | ### 返回值 `dict`: 合并后的字典。如果某个键出现多次: - 第一次:直接赋值; - 第二次及以上:转换为列表并追加。 ### 示例 ```python data = {'name': 'Alice', 'hobby': 'reading', 'hobby': 'coding'} # 实际输入可能是 MultiDict({'hobby': ['reading', 'coding']}) result = multiDict2Dict(data) # result == {'name': 'Alice', 'hobby': ['reading', 'coding']} ``` > ⚠️ 注意:Python 字典本身不允许多个相同键,此函数适用于模拟场景或多值结构(如 Flask 的 `request.args`)。 --- ## Class: `DictObjectEncoder(JSONEncoder)` 用于将 `DictObject` 实例序列化为 JSON 的自定义编码器。 ### 方法 #### `.default(o)` 重写父类方法,当遇到无法序列化的对象时调用。 ##### 参数 - `o`: 待序列化的对象。 ##### 行为 调用对象的 `_addon()` 方法获取可序列化数据(需用户自行实现 `_addon` 方法)。 ⚠️ 当前实现依赖于对象存在 `_addon()` 方法,否则会报错。 ##### 示例 ```python class MyObj(DictObject): def _addon(self): return {"custom": "value"} json.dumps(MyObj(), cls=DictObjectEncoder) # 输出: {"custom": "value"} ``` > 💡 提示:若未定义 `_addon()`,应避免直接使用此编码器。 --- ## Class: `DictObject(dict)` 一个继承自 `dict` 的增强字典类,支持属性式访问、嵌套包装和深拷贝。 ### 初始化 ```python obj = DictObject(key=value, other=[1,2]) # 或 obj = DictObject({'key': 'value'}) ``` ### 特性 - 支持 `obj.key` 获取/设置 `obj['key']` - 自动递归包装嵌套的 `dict` 和 `list` - 访问不存在的属性返回 `None`(不抛异常) - 支持 `del obj.key` 删除键 --- ### 方法概览 | 方法 | 说明 | |------|------| | `__getattr__(key)` | 属性取值,不存在返回 `None` | | `__setattr__(key, value)` | 设置属性 | | `__delattr__(key)` | 删除属性,不存在则抛 `AttributeError` | | `__setitem__(key, value)` | 设置项,并自动包装值 | | `update(*args, **kwargs)` | 更新字典,自动包装新值 | | `to_dict()` | 转换为普通嵌套字典 | | `copy()` | 深拷贝当前对象 | | `_wrap(value)` *(static)* | 包装 dict/list 为 DictObject | | `_dict(value)` *(static)* | 解包 DictObject 为原生 dict | --- ### 详细方法说明 #### `__init__(*args, **kwargs)` 初始化 `DictObject` 实例,并立即更新所有传入的数据。 ##### 示例 ```python d = DictObject(a=1, b={'x': 2}) print(d.b.x) # 输出: 2 ``` --- #### `__getattr__(key)` 使你可以使用点语法访问字典键。 - 成功:返回对应值。 - 失败:返回 `None`(原被注释的 `raise AttributeError` 已禁用)。 > 🛑 不推荐用于判断是否存在字段,请使用 `in` 操作符。 ##### 示例 ```python obj = DictObject(name="Bob") print(obj.name) # "Bob" print(obj.age) # None ``` --- #### `__setattr__(key, value)` 允许通过 `obj.key = value` 设置字典键值。 内部调用 `self[key] = value`。 ##### 示例 ```python obj = DictObject() obj.city = "Beijing" print(obj['city']) # "Beijing" ``` --- #### `__delattr__(key)` 删除指定属性(即字典键)。 - 若键不存在,抛出 `AttributeError`。 - 否则从字典中移除该键。 ##### 示例 ```python del obj.city # 等价于 del obj['city'] ``` --- #### `__setitem__(key, value)` 设置键值对,并通过 `_wrap()` 自动包装值。 这意味着嵌套的字典会被自动转为 `DictObject`。 ##### 示例 ```python obj['nested'] = {'a': 1} print(type(obj['nested'])) # ``` --- #### `update(*args, **kwargs)` 批量更新字典内容,所有新增值都会经过 `_wrap()` 处理。 ##### 示例 ```python obj.update({'list': [1, {'deep': 2}]}) print(type(obj.list[1])) # DictObject ``` --- #### `to_dict()` 将整个 `DictObject` 结构递归转换为原始的 Python 原生字典(去除 `DictObject` 类型)。 ##### 返回 `dict`: 完全由 `dict`, `list`, 基本类型组成的结构,适合 JSON 序列化。 ##### 示例 ```python obj = DictObject(a=DictObject(b=2)) plain = obj.to_dict() print(plain) # {'a': {'b': 2}} ``` --- #### `copy()` 创建一个深拷贝副本,包括所有嵌套结构都重新包装。 > ⚠️ 并非完全等同于 `copy.deepcopy()`,但对常见结构足够安全。 ##### 返回 新的 `DictObject` 实例。 ##### 示例 ```python new_obj = obj.copy() new_obj.a.b = 999 # 不影响原始 obj ``` --- #### `@staticmethod _wrap(value)` 递归包装输入值中的 `dict` 和 `list`。 ##### 规则 - `dict` → `DictObject(dict)` - `list` → `[ _wrap(item) for item in list ]` - 其他类型保持不变 ##### 示例 ```python wrapped = DictObject._wrap({'x': {'y': 1}}) print(type(wrapped)) # DictObject print(type(wrapped['x'])) # DictObject ``` --- #### `@staticmethod _dict(value)` 与 `_wrap` 相反,将 `DictObject` 或其嵌套结构还原为原生 `dict` / `list`。 ##### 规则 - `DictObject` → `.to_dict()` - `list` → 递归处理每个元素 - 其他类型原样返回 ##### 示例 ```python data = DictObject._dict(obj) # data 是纯 dict/list 结构 ``` --- ## 已注释掉的工厂函数 `dictObjectFactory`(建议扩展用) 该函数原本设计用于根据类名动态创建特定子类实例。 ```python # 示例原型(当前被注释): # obj = dictObjectFactory("User", name="Tom", age=30) ``` ### 功能逻辑(潜在用途) 1. 查找 `DictObject` 的子类中哪个满足 `isMe(_klassName__) == True` 2. 若找到,则实例化该子类;否则回退到 `DictObject` > ✅ 可作为插件式对象注册机制的基础,适合 ORM 或配置系统。 ### 当前状态 - 被注释,暂未启用。 - 使用时需确保各子类实现了 `isMe(class_name)` 类方法。 --- ## 使用示例 ### 示例 1:基础用法 ```python user = DictObject( name="Alice", profile={"age": 28, "city": "Shanghai"}, hobbies=["reading", "hiking"] ) print(user.name) # Alice print(user.profile.city) # Shanghai user.email = "alice@example.com" print(user.email) # alice@example.com ``` ### 示例 2:JSON 序列化 ```python class Person(DictObject): def _addon(self): return self.to_dict() # 或添加额外元信息 p = Person(name="Bob", info={"job": "Engineer"}) json_str = json.dumps(p, cls=DictObjectEncoder, indent=2) print(json_str) # { # "name": "Bob", # "info": { # "job": "Engineer" # } # } ``` ### 示例 3:多值字典处理 ```python form_data = {'tag': 'python', 'tag': 'web', 'author': 'admin'} # 实际可能是 MultiDict({'tag': ['python', 'web'], 'author': ['admin']}) flat = multiDict2Dict(form_data) print(flat['tag']) # ['python', 'web'] (如果是真实多值) ``` --- ## 注意事项与限制 | 项目 | 说明 | |------|------| | ❌ `__getattr__` 返回 `None` | 导致无法区分“无此属性”和“属性值为 None” | | ⚠️ `_addon()` 必须实现 | 否则 `DictObjectEncoder` 会失败 | | 🔁 `_wrap` 是递归的 | 大型嵌套结构可能影响性能 | | 🧩 子类工厂未启用 | 如需动态构造,请解注并完善 `isMe()` 逻辑 | | 📦 不支持 tuple/set 自动包装 | 仅处理 `dict` 和 `list` | --- ## 总结 `DictObject` 提供了一种简洁优雅的方式来处理嵌套数据结构,特别适用于: - 配置文件解析(YAML/JSON) - API 响应数据建模 - Web 请求参数处理 - 构建轻量级数据传输对象(DTO) 结合 `multiDict2Dict` 和 `DictObjectEncoder`,可在前后端交互、日志记录、序列化等场景中大幅提升开发效率。 --- 📌 **建议改进方向**: - 添加类型提示(Type Hints) - 引入 `__dir__()` 支持 IDE 自动补全 - 实现更健壮的工厂模式或注册中心 - 增加单元测试覆盖率 --- 📄 *文档版本:v1.0* 📅 *最后更新:2025-04-05*