为何带默认值的dataclasses InitVar会被设为实例属性?
Python Dataclass中带默认值的InitVar实例属性问题
在Python数据类(dataclass)中存在一个特殊行为:当为InitVar类型的变量设置默认值时,该变量会被保留为实例属性;而无默认值的InitVar变量,则会在dataclasses._process_class()处理阶段被主动删除。
代码验证现象
以下代码可直观观察这一行为:
from dataclasses import dataclass, InitVar, fields @dataclass class HasDefault: abc: int = 18 xyz: InitVar[str] = 'oops' def __post_init__(self, xyz): self.abc += len(xyz) @dataclass class NoHasDefault: abc: int xyz: InitVar[str] def __post_init__(self, xyz): self.abc += len(xyz) hd = HasDefault(abc=42, xyz='so long...') print('field names', [field.name for field in fields(hd)]) print(hd, hd.abc, hd.xyz) print() hd2 = HasDefault(abc=42) print('field names', [field.name for field in fields(hd2)]) print(hd2, hd2.abc, hd2.xyz) print() hd3 = HasDefault() print('field names', [field.name for field in fields(hd3)]) print(hd3, hd3.abc, hd3.xyz) print() nhd = NoHasDefault(abc=42, xyz='so long...') print('field names', [field.name for field in fields(nhd)]) print(nhd, getattr(nhd, 'xyz', 'no attribute xyz'))
运行结果:
field names ['abc'] HasDefault(abc=52) 52 oops field names ['abc'] HasDefault(abc=46) 46 oops field names ['abc'] HasDefault(abc=22) 22 oops field names ['abc'] NoHasDefault(abc=52) no attribute xyz
疑问与矛盾点
InitVar的设计初衷是仅用于初始化流程(传递给__post_init__),不应成为实例的持久属性。但带默认值的InitVar却会被保留为实例属性,这是否属于Python dataclass的bug?
另外,类型检查工具mypy会报错提示此类实例不存在xyz属性,说明mypy对InitVar的处理逻辑与Python运行时行为不一致。
ruamel.yaml的特殊处理
在使用版本>0.17.34的ruamel.yaml加载包含带默认值InitVar的数据类时,需要额外处理以避免YAML映射中的值覆盖默认值,示例代码如下:
from dataclasses import dataclass, InitVar from typing import ClassVar from ruamel.yaml import YAML yaml = YAML() @yaml.register_class @dataclass class HasDefault: yaml_tag: ClassVar = '!has_default' # 不设置则使用类名作为tag('!HasDefault') abc: int xyz: InitVar[str] = 'oops' def __post_init__(self, xyz): self.abc += len(xyz) yaml_str = """ !has_default abc: 42 xyz: hello world """ data = yaml.load(yaml_str) print(data, data.xyz == 'oops')
运行结果:
HasDefault(abc=53) True
如果不做此处理,data.xyz的值会被YAML中的'hello world'覆盖。
内容的提问来源于stack exchange,提问作者Anthon
相关产品推荐
相关产品推荐

