9.6 KiB
以下是为提供的 Python 代码编写的 Markdown 格式技术文档,涵盖了功能说明、类与函数的详细描述、使用示例等。
DictObject 模块技术文档
本模块提供了一个增强型字典对象 DictObject,支持通过属性访问键值(如 obj.key),并可递归封装嵌套数据结构。同时提供了 JSON 序列化支持和多值字典转单值/列表字典的工具函数。
目录
- 核心功能概述
- 函数
multiDict2Dict - 类
DictObjectEncoder - 类
DictObject - 辅助静态方法
_wrap和_dict - 已注释工厂函数
dictObjectFactory - 使用示例
- 注意事项与限制
核心功能概述
该模块主要实现以下功能:
- 属性式访问字典:允许像操作对象属性一样读写字典内容。
- 自动类型包装:对嵌套的字典或列表自动转换为
DictObject或其列表形式。 - 安全访问机制:访问不存在的属性返回
None而非抛出异常。 - JSON 可序列化支持:通过自定义编码器支持复杂对象的 JSON 输出。
- 多值字典合并工具:将多个同名键的值合并为列表。
Function: multiDict2Dict(md)
将一个多值字典(如 Web 表单中常见的多个同名参数)转换为标准字典,若某键有多个值,则将其合并为一个列表。
参数
| 参数 | 类型 | 说明 |
|---|---|---|
md |
dict 或 MultiDict |
输入的多值字典 |
返回值
dict: 合并后的字典。如果某个键出现多次:
- 第一次:直接赋值;
- 第二次及以上:转换为列表并追加。
示例
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() 方法,否则会报错。
示例
class MyObj(DictObject):
def _addon(self):
return {"custom": "value"}
json.dumps(MyObj(), cls=DictObjectEncoder)
# 输出: {"custom": "value"}
💡 提示:若未定义
_addon(),应避免直接使用此编码器。
Class: DictObject(dict)
一个继承自 dict 的增强字典类,支持属性式访问、嵌套包装和深拷贝。
初始化
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 实例,并立即更新所有传入的数据。
示例
d = DictObject(a=1, b={'x': 2})
print(d.b.x) # 输出: 2
__getattr__(key)
使你可以使用点语法访问字典键。
- 成功:返回对应值。
- 失败:返回
None(原被注释的raise AttributeError已禁用)。
🛑 不推荐用于判断是否存在字段,请使用
in操作符。
示例
obj = DictObject(name="Bob")
print(obj.name) # "Bob"
print(obj.age) # None
__setattr__(key, value)
允许通过 obj.key = value 设置字典键值。
内部调用 self[key] = value。
示例
obj = DictObject()
obj.city = "Beijing"
print(obj['city']) # "Beijing"
__delattr__(key)
删除指定属性(即字典键)。
- 若键不存在,抛出
AttributeError。 - 否则从字典中移除该键。
示例
del obj.city
# 等价于 del obj['city']
__setitem__(key, value)
设置键值对,并通过 _wrap() 自动包装值。
这意味着嵌套的字典会被自动转为 DictObject。
示例
obj['nested'] = {'a': 1}
print(type(obj['nested'])) # <class 'DictObject'>
update(*args, **kwargs)
批量更新字典内容,所有新增值都会经过 _wrap() 处理。
示例
obj.update({'list': [1, {'deep': 2}]})
print(type(obj.list[1])) # DictObject
to_dict()
将整个 DictObject 结构递归转换为原始的 Python 原生字典(去除 DictObject 类型)。
返回
dict: 完全由 dict, list, 基本类型组成的结构,适合 JSON 序列化。
示例
obj = DictObject(a=DictObject(b=2))
plain = obj.to_dict()
print(plain) # {'a': {'b': 2}}
copy()
创建一个深拷贝副本,包括所有嵌套结构都重新包装。
⚠️ 并非完全等同于
copy.deepcopy(),但对常见结构足够安全。
返回
新的 DictObject 实例。
示例
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 ]- 其他类型保持不变
示例
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→ 递归处理每个元素- 其他类型原样返回
示例
data = DictObject._dict(obj)
# data 是纯 dict/list 结构
已注释掉的工厂函数 dictObjectFactory(建议扩展用)
该函数原本设计用于根据类名动态创建特定子类实例。
# 示例原型(当前被注释):
# obj = dictObjectFactory("User", name="Tom", age=30)
功能逻辑(潜在用途)
- 查找
DictObject的子类中哪个满足isMe(_klassName__) == True - 若找到,则实例化该子类;否则回退到
DictObject
✅ 可作为插件式对象注册机制的基础,适合 ORM 或配置系统。
当前状态
- 被注释,暂未启用。
- 使用时需确保各子类实现了
isMe(class_name)类方法。
使用示例
示例 1:基础用法
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 序列化
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:多值字典处理
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