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

9.4 KiB
Raw Blame History

DictObject 技术文档

# DictObject - 字典对象封装库

`DictObject` 是一个轻量级的 Python 工具类,用于将字典(`dict`)转换为支持属性访问的对象,并提供丰富的数据操作、序列化与嵌套结构处理能力。它允许通过点号语法访问字典键值,同时保留了标准字典的操作接口。

---

## 目录

- [功能概览](#功能概览)
- [依赖说明](#依赖说明)
- [核心函数](#核心函数)
  - [`multiDict2Dict(md)`](#multidict2dictmd)
- [核心类](#核心类)
  - [`DictObject`](#dictobject)
  - [`DictObjectEncoder`](#dictobjectencoder)
- [工厂方法](#工厂方法)
  - [`dictObjectFactory(_klassName__, **kwargs)`](#dictobjectfactory_klassname__-kwargs)
- [使用示例](#使用示例)
- [注意事项](#注意事项)

---

## 功能概览

- 将普通字典转为可点式访问的 `DictObject` 对象。
- 支持嵌套字典、列表、元组自动转换。
- 提供类似字典的标准方法(如 `.items()`, `.get()`, `.pop()` 等)。
- 可过滤内置函数、方法等不可序列化的类型。
- 支持 JSON 序列化(配合 `DictObjectEncoder`)。
- 支持继承和动态子类查找的工厂模式创建实例。

---

## 依赖说明

```python
import json
from json import JSONEncoder
from inspect import ismethod, isfunction, isbuiltin, isabstract
  • json: 用于 JSON 编码/解码。
  • JSONEncoder: 自定义 JSON 编码器基类。
  • inspect 模块:
    • ismethod, isfunction: 判断是否为方法或函数。
    • isbuiltin: 判断是否为内置函数。
    • isabstract: 判断是否为抽象方法(用于排除不可序列化对象)。

核心函数

multiDict2Dict(md)

将可能包含重复键的多值字典(如 Web 表单提交中的 MultiDict)转换为标准字典。若某键对应多个值,则将其合并为列表。

参数

参数 类型 说明
md dictMultiDict 输入字典,可能含有重复键

返回值

  • dict: 转换后的字典。若某个键有多个值,则其值为列表;否则保持原样。

示例

d = {'a': 1, 'b': 2, 'a': 3}
result = multiDict2Dict(d)
# result => {'a': [1, 3], 'b': 2}

实现逻辑

  • 遍历输入字典;
  • 若键不存在,直接赋值;
  • 若已存在且原值是列表,追加新值;
  • 否则将原值和新值构造成列表。

核心类

DictObject

一个可动态扩展、支持属性访问的字典封装类。

初始化:__init__(**kw)

接受关键字参数初始化对象。

参数
参数 类型 说明
**kw dict 关键字参数集合
行为
  • 记录初始属性名到 org_keys__
  • 使用 __DOitem(v) 处理每个值(递归构建嵌套结构);
  • 调用 update() 更新内部 __dict__

属性访问:__getattr__(name)

当调用未定义属性时,尝试从 _addon() 中获取该键的值。

  • 如果存在,返回对应值;
  • 否则返回 None

⚠️ 注意:这不会触发 AttributeError,需注意潜在静默失败问题。


方法列表

方法 功能
update(kw) 更新对象属性(仅添加或修改非原始属性)
_addon() 获取用户添加的所有属性组成的字典(排除构造时的原始属性)
clear() 清除所有动态添加的属性
get(name, default=None) 获取指定属性,不存在返回默认值
pop(k, default=None) 删除并返回属性值
popitem() 删除并返回任意一个 (key, value) 对
items() / keys() / values() 返回动态属性的视图对象(类似字典)
__getitem__(name) 支持 obj['key'] 语法访问
__setitem__(name, value) 支持 obj['key'] = value 语法设置
__delitem__(key) 支持 del obj['key'] 删除属性
__str__() 输出动态属性的字符串表示(即 str(_addon())
__expr__() 存在错误:应为 __repr__,当前实现无效
copy() 返回动态属性的浅拷贝字典
to_dict() 深度转换为纯 dict(移除不可序列化内容)
dict_to_dict(dic) 递归转换字典,处理嵌套 DictObject、函数、内置对象等
array_to_dict(v) 递归转换数组/元组,跳过函数等不可序列化项
__DOArray(a) 将列表/元组中每一项用 __DOitem 处理
__DOitem(i) 根据输入类型决定是否转换为 DictObject 或递归处理

特殊方法说明

to_dict()dict_to_dict()

用于深度清理对象,生成可用于 JSON 序列化的纯净字典。

  • 递归遍历嵌套结构;
  • 自动识别并转换:
    • DictObject → 调用 .to_dict()
    • dict → 递归调用 dict_to_dict
    • list/tuple → 调用 array_to_dict
  • 过滤以下类型(不包含在输出中):
    • 内置函数(__builtins__
    • 函数、方法、内建函数、抽象方法(使用 inspect 判断)
__DOitem(i)

对传入值进行类型判断并包装:

输入类型 处理方式
DictObject 直接返回
dict 过滤非字符串键后构造新的 DictObject(**i)
listtuple 转换为 [ __DOitem(x) for x in i ]
其他 原样返回

⚠️ 异常处理:构造失败时打印调试信息并重新抛出异常。


类方法

@classmethod isMe(cls, name)

判断类名是否等于 'DictObject'

用于工厂函数中判断目标类。


DictObjectEncoder(JSONEncoder)

自定义 JSON 编码器,用于将 DictObject 实例序列化为 JSON。

方法:default(o)

重写 JSONEncoder.default(),返回对象的 _addon() 字典。

示例
obj = DictObject(name="Alice", age=30)
json_str = json.dumps(obj, cls=DictObjectEncoder)
# 输出: {"name": "Alice", "age": 30}

支持嵌套结构序列化(前提是已通过 to_dict() 处理干净)。


工厂方法

dictObjectFactory(_klassName__, **kwargs)

根据类名字符串动态创建 DictObject 或其子类的实例。

参数

参数 类型 说明
_klassName__ str 类名(如 'DictObject'
**kwargs dict 构造参数

返回值

  • DictObject 或其子类的实例。

内部函数:findSubclass(_klassName__, klass)

递归查找 klass 的所有子类中满足 isMe(_klassName__) 的类。

流程

  1. 若类名为 'DictObject',直接返回 DictObject(**kwargs)
  2. 否则递归查找子类;
  3. 找到则调用该子类构造函数;
  4. 未找到仍返回 DictObject 实例;
  5. 出错时打印日志并抛出异常。

支持插件式扩展:可通过继承 DictObject 并重写 isMe() 实现自定义类匹配。


使用示例

1. 基本用法:属性访问

data = {'name': 'Bob', 'age': 25, 'city': 'Beijing'}
obj = DictObject(**data)

print(obj.name)           # Bob
print(obj['age'])         # 25
print(obj.get('city'))    # Beijing

2. 嵌套字典自动转换

nested = {
    'user': {
        'id': 1,
        'profile': {'name': 'Alice', 'tags': ['dev', 'py']}
    }
}
obj = DictObject(**nested)
print(obj.user.profile.name)  # Alice
print(obj.to_dict())
# {'user': {'id': 1, 'profile': {'name': 'Alice', 'tags': ['dev', 'py']}}}

3. JSON 序列化

import json
from dictObject import DictObject, DictObjectEncoder

obj = DictObject(title="My App", version=1.0)
json_str = json.dumps(obj, cls=DictObjectEncoder, indent=2)
print(json_str)

输出:

{
  "title": "My App",
  "version": 1.0
}

4. 工厂模式创建对象

# 假设有子类 MyData 继承 DictObject 并重写了 isMe()
class MyData(DictObject):
    @classmethod
    def isMe(cls, name):
        return name == 'MyData'

obj = dictObjectFactory('MyData', x=1, y=2)
print(type(obj))  # <class '__main__.MyData'>

注意事项

  1. __expr__ 方法命名错误

    • 正确应为 __repr__,当前 __expr__ 不会被 Python 解释器调用。
    • 建议修复为:
      def __repr__(self):
          return repr(self._addon())
      
  2. __builtins__ 过滤不完全可靠

    • 当前只检查键名为 '__builtins__',建议增强检测逻辑。
  3. 性能考虑

    • 每次调用 _addon() 都会重新计算差异,频繁调用可能影响性能。
    • 可缓存结果或改用更高效的数据结构。
  4. 异常处理

    • __DOitem 中捕获异常后打印信息但继续抛出,适合开发调试。
    • 生产环境建议记录日志而非打印。
  5. 线程安全性

    • 未做线程安全设计,多线程环境下慎用共享实例。
  6. 内存泄漏风险

    • org_keys__ 记录初始属性,若后续手动增删较多,可能导致 _addon() 判断不准。

总结

DictObject 是一个灵活实用的字典对象封装工具适用于配置管理、API 数据解析、动态对象构建等场景。结合 dictObjectFactoryDictObjectEncoder,可实现高度可扩展的数据模型系统。

推荐用于快速原型开发、DSL 设计、Web 请求参数封装等领域。

🔧 建议改进点:

  • 修复 __expr____repr__
  • 添加 __contains__, __len__ 支持
  • 提供 from_dict() 类方法
  • 支持冻结模式(防止修改)

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