如何解决pydantic中__fields_set__方法返回空集合的问题?

问题现象与背景

当开发者使用pydantic的__fields_set__方法时,经常会遇到返回空集合的意外情况。这个内置属性本应记录模型初始化时实际被赋值的字段集合,但在以下场景会出现异常:

  • 使用construct()方法绕过验证创建模型实例
  • 嵌套模型中的字段未被显式赋值
  • 动态字段通过Config.extra允许但未被追踪

根本原因分析

通过分析pydantic v1.10.x源码发现,__fields_set__的异常行为主要涉及三个核心机制:

  1. 字段验证触发器:仅在__init__parse_obj等标准入口触发字段跟踪
  2. 数据污染检测:当使用dict.update()等非标准方式修改属性时不会更新集合
  3. 继承链断裂:子类覆盖父类字段时若未正确调用super()会导致跟踪丢失

五种解决方案对比

方案 适用场景 性能影响
改用model_dump(exclude_unset=True) 序列化场景
显式调用__init__而非construct 模型初始化
自定义__fields_set__属性 动态字段管理

最佳实践示例

from pydantic import BaseModel

class User(BaseModel):
    name: str
    age: int = None

    # 解决方案:强制初始化追踪
    def __init__(self, **data):
        super().__init__(**data)
        self.__fields_set__.update(data.keys())

user = User(name="Alice")
print(user.__fields_set__)  # 输出: {'name'}

性能优化建议

对于高频调用的模型,建议:

  • 避免在循环中重复检查__fields_set__
  • 对只读模型使用frozen=True配置
  • 考虑使用@validator替代字段集合检查

版本兼容性说明

注意不同版本的行为差异:

  • v1.x:字段集合可能包含未通过验证的字段
  • v2.x:严格模式会过滤无效字段