当您为数据类中的
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
为什么属性
xyz
为 InitVar
类型变量设置 at all(当有默认值时)?我希望永远不会设置此属性,因为它仅用于初始化。这是一个错误吗?
mypy
实际上抱怨这些实例没有属性xyz
,所以它似乎以不同的方式处理InitVar
。
因此,我需要添加一些额外的行来加载这样的
dataclass
从 YAML 以相同的方式工作,通常是来自 YAML 映射的值
将用于设置属性,而不是默认值。所以你可以做的(在 `ruamel.yaml>0.17.34 中)是:
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' # if not set the class name is taken ('!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
将等于 hello world
为什么要为 InitVar 类型变量设置属性 xyz(当有默认值时)?我希望永远不会设置此属性,因为它仅用于初始化。这是bug吗?
医生说:
如果一个字段是
,则它被视为伪字段,称为伪字段 仅初始化字段。由于它不是一个真实的字段,因此它不会被返回 模块级InitVar
函数。仅初始化字段添加为 生成的fields()
方法的参数,并传递给 可选的__init__()
方法。它们不被以其他方式使用 数据类。__post_init__
因此 dataclasses 仅从
InitVars
上下文中排除 fields
。
但是提到的短语 “仅初始化字段作为参数添加到生成的 __init__()
方法” 意味着这些仍将在初始化阶段作为类属性添加。
另一个细微差别是我们不允许混合默认/非默认
initVars
,例如:
@dataclass
class HasDefault:
abc: int = 18
xyz: InitVar[str]
iv: InitVar[int] = ''
def __post_init__(self, xyz, iv):
self.abc += len(xyz)
因为它会抛出错误:
TypeError: non-default argument 'xyz' follows default argument