Python attrs库属性初始化及校验执行顺序疑问
问题原因
这是attrs库内置的初始化、校验执行顺序设计导致的,attrs生成的__init__方法固定执行逻辑如下:
- 按类中属性定义的先后顺序,逐个完成属性值的解析与赋值:
- 优先取调用时传入的参数值,无传入则使用默认值/执行默认工厂(
takes_self=True的工厂可直接访问已完成赋值的前置属性) - 该阶段仅完成赋值,不会触发任何属性校验
- 优先取调用时传入的参数值,无传入则使用默认值/执行默认工厂(
- 所有属性全部赋值完成后,才会按定义顺序逐个执行所有属性的校验器。
对应你的代码执行流程:
- 调用
Bar("5")后,先处理第一个属性x,直接将传入的字符串"5"赋值给self.x,不触发校验 - 接着处理第二个属性
foo,无传入参数,执行绑定的工厂方法,拿已赋值的self.x="5"初始化Foo Foo初始化时触发自身的属性校验,检测到x为字符串直接抛出异常,此时Bar自身的校验流程还未启动,所以你看不到Bar的x属性校验报错。
符合预期的修改方案
如果要实现「先完成Bar的所有属性校验,再初始化Foo」的逻辑,可以将Foo的初始化逻辑放到__attrs_post_init__中执行,该钩子方法的调用时机是所有属性校验完成之后:
@attr.mutable class Foo: x: int = attr.ib(validator=attr.validators.instance_of(int)) @attr.mutable class Bar: x: int = attr.ib(validator=attr.validators.instance_of(int)) # 关闭foo的初始化参数传入,赋值逻辑移到post_init中 foo: Foo = attr.ib(init=False, validator=attr.validators.instance_of(Foo)) def __attrs_post_init__(self): self.foo = Foo(self.x) if __name__ == "__main__": Bar("5")
修改后运行代码,会先触发Bar的x属性校验抛出类型错误,符合你的预期。
内容的提问来源于stack exchange,提问作者NI6
相关产品推荐
相关产品推荐

