← 中文资源

简体中文版本

在 __post_init__ 中校验数据类字段

在数据类构造阶段检查邮箱、年龄和用户名,先归一化再收集全部错误,最后一次性抛出包含字段名的校验异常。

阅读英文原文

功能说明

Signup.__post_init__ 在对象构造完成后立即校验字段:邮箱去空格并转小写,年龄必须是真正的整数且在 13 到 120 之间,用户名长度 3 到 20 且只允许字母、数字与下划线。所有错误先收集到字典里,最后一次性抛出 ValidationError,因此调用方可以一次看到全部问题,而不是修一个再报一个。

关键代码

if isinstance(self.age, bool) or not isinstance(self.age, int):
    errors["age"] = "must be an integer"
elif not 13 <= self.age <= 120:
    errors["age"] = "must be between 13 and 120"
...
if errors:
    raise ValidationError(errors)

在 Python 中 bool 是 int 的子类,所以必须先把 True 排除,否则它会被当成年龄 1。

使用注意

  • __post_init__ 在 __init__ 之后运行,对普通数据类有效;使用 frozen=True 时需要改用 object.__setattr__ 才能归一化字段。
  • 校验只发生在构造时,之后直接修改属性不会被再次检查。
  • 错误字典的插入顺序就是字段检查顺序,输出稳定。
  • 归一化后的值写回 self,调用方拿到的对象已经是清理过的数据。
  • 复杂项目可以换成 Pydantic 或 attrs 的校验器,但这里没有额外依赖。

验证方式

示例应打印一个邮箱已转小写、用户名已去空格的 Signup 对象;第二组参数会触发三条错误,异常消息以分号连接,error.errors 中可以按字段读取。可以分别传入 True、12 和带空格的用户名验证边界。