类字段初始化顺序取决于类型和python类创建流程:类变量在类定义时按代码顺序执行;实例字段仅在__init__中通过self赋值时初始化,需显式调用super().__init__();dataclass字段须无默认值字段在前,且跨父子类校验;__init_subclass__用于类构建干预,不初始化字段。

类字段的初始化顺序,和你写的“谁先定义”关系不大,关键看字段类型和 Python 的类创建流程。静态字段(类变量)在类体执行时就完成赋值;而实例字段(比如写在 __init__ 里的 self.x = ...)要等到实例化时才运行。父类和子类的字段不是按“继承顺序”依次初始化的,而是分阶段、按作用域分别处理的。
类变量(静态字段):定义即执行,按代码顺序逐行
类体中直接写的赋值语句,属于类变量,会在类对象构建阶段执行——也就是 import 或执行到 class 语句时。Python 从上到下解释类体,遇到一行赋值就执行一行。
- 父类的类变量,在父类定义时就初始化完毕
- 子类的类变量,在子类定义时才初始化,此时父类早已存在
- 如果子类里写了 count = len(__subclasses__()) 这类依赖父类状态的表达式,它看到的是当前已加载的子类列表(不含自己,因自身尚未注册完成)
实例字段:只在 __init__ 中触发,严格依赖调用链
实例字段不是“自动继承并初始化”的。它们只在 __init__ 方法里通过 self.attr = value 赋值才产生,且必须由开发者显式控制执行时机。
- 父类 __init__ 不会自动运行,必须用 super().__init__() 显式调用
- 子类 __init__ 里没写 super(),父类字段(如 self.name)根本不会存在
- 即使父类字段有默认值,子类也得靠调用父类 __init__ 才能获得它;否则访问会报 AttributeError
dataclass 字段:隐式生成 __init__,但顺序约束更严
使用 @dataclass 时,字段声明本身不执行初始化,真正逻辑藏在自动生成的 __init__ 中。但 Python 强制要求:所有无默认值的字段必须排在有默认值的字段之前——这个限制跨父子类生效。
- 若父类 dataclass 有 a: int(无默认),子类加了 b: str = "x"(有默认),就会报错
- 解决办法是让父类字段也带默认值,或改用 field(default_factory=...)
- 字段顺序最终决定 __init__ 参数顺序,影响调用时的位置传参是否合法
__init_subclass__:不初始化字段,但能干预类构建过程
__init_subclass__ 在子类定义完成、绑定到命名空间前被调用。它不碰实例字段,也不执行 __init__,但它能读取子类的类变量、注解、甚至装饰器信息,做注册、校验或动态补全。
- 例如检查子类是否定义了必要类变量 required_config
- 可为子类自动添加类属性:cls.version = "1.0"
- 不能访问 self,因为它运行时还没有任何实例,连 __new__ 都没发生











