apppublic/aidocs/dictObject.md
2025-10-05 11:23:33 +08:00

372 lines
9.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

以下是为提供的 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'])) # <class 'DictObject'>
```
---
#### `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
```
### 示例 2JSON 序列化
```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*