You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python attrs库属性初始化及校验执行顺序疑问

问题原因

这是attrs库内置的初始化、校验执行顺序设计导致的,attrs生成的__init__方法固定执行逻辑如下:

  1. 按类中属性定义的先后顺序,逐个完成属性值的解析与赋值:
    • 优先取调用时传入的参数值,无传入则使用默认值/执行默认工厂(takes_self=True的工厂可直接访问已完成赋值的前置属性)
    • 该阶段仅完成赋值,不会触发任何属性校验
  2. 所有属性全部赋值完成后,才会按定义顺序逐个执行所有属性的校验器。

对应你的代码执行流程:

  • 调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 07:39:03