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

9.6 KiB
Raw Permalink Blame History

以下是为提供的 Python 代码编写的 Markdown 格式技术文档,涵盖了功能说明、类与函数的详细描述、使用示例等。


DictObject 模块技术文档

本模块提供了一个增强型字典对象 DictObject,支持通过属性访问键值(如 obj.key),并可递归封装嵌套数据结构。同时提供了 JSON 序列化支持和多值字典转单值/列表字典的工具函数。

目录


核心功能概述

该模块主要实现以下功能:

  1. 属性式访问字典:允许像操作对象属性一样读写字典内容。
  2. 自动类型包装:对嵌套的字典或列表自动转换为 DictObject 或其列表形式。
  3. 安全访问机制:访问不存在的属性返回 None 而非抛出异常。
  4. JSON 可序列化支持:通过自定义编码器支持复杂对象的 JSON 输出。
  5. 多值字典合并工具:将多个同名键的值合并为列表。

Function: multiDict2Dict(md)

将一个多值字典(如 Web 表单中常见的多个同名参数)转换为标准字典,若某键有多个值,则将其合并为一个列表。

参数

参数 类型 说明
md dictMultiDict 输入的多值字典

返回值

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']
  • 自动递归包装嵌套的 dictlist
  • 访问不存在的属性返回 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)

递归包装输入值中的 dictlist

规则
  • dictDictObject(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)

功能逻辑(潜在用途)

  1. 查找 DictObject 的子类中哪个满足 isMe(_klassName__) == True
  2. 若找到,则实例化该子类;否则回退到 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

示例 2JSON 序列化

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 自动包装 仅处理 dictlist

总结

DictObject 提供了一种简洁优雅的方式来处理嵌套数据结构,特别适用于:

  • 配置文件解析YAML/JSON
  • API 响应数据建模
  • Web 请求参数处理
  • 构建轻量级数据传输对象DTO

结合 multiDict2DictDictObjectEncoder,可在前后端交互、日志记录、序列化等场景中大幅提升开发效率。


📌 建议改进方向

  • 添加类型提示Type Hints
  • 引入 __dir__() 支持 IDE 自动补全
  • 实现更健壮的工厂模式或注册中心
  • 增加单元测试覆盖率

📄 文档版本v1.0
📅 最后更新2025-04-05