不是“@dataclass
由解释器解释”,因为解释器不“知道”它必须引发类似TypeError: non-default argument 'b' follows default argument
. 相反,@dataclass
它是一个常规的 Python 函数,它检查类对象并显式引发错误。
这种机制的高级描述是field
返回一个包含传递给的元数据的Field
对象field
。@dataclass
代码检查类属性值是否是Field
对象,而不是它们是否是由创建的field
——如果需要,可以编写一个自定义函数来构造一个Field
实例。
当然,最简单的方法就是拥有一个调用函数field
来创建一个Field
.
from dataclasses import field, MISSING
def auto_field(*, default=MISSING, default_factory=MISSING, init=True, metadata=None):
"""Field that inspects defaults to decide whether it is repr/hash'able"""
if default is MISSING and default_factory is MISSING:
return field(init=init, metadata=metadata)
test_default = default if default is not MISSING else default_factory()
return field(
default=default, default_factory=default_factory, init=init, metadata=metadata,
repr=type(test_default).__repr__ is not object.__repr__,
hash=getattr(test_default, '__hash__', None) is not None,
compare=getattr(test_default, '__hash__', None) is not None,
)
from dataclasses import dataclass
@dataclass(frozen=True)
class Foo:
a: int = auto_field() # not counted as a default
b: int
c: list = auto_field(default_factory=list)
print(Foo(12, 42), hash(Foo(12, 42))) # works because c is ignored for hashing
请注意,从概念上讲,仍然受限于 ofdataclass
及其Field
s 的逻辑。例如,这意味着不能创建“具有默认值但不被视为默认值的字段”——这取决于人们如何接近它,dataclass
要么忽略它,要么在准备实际类时仍然引发错误。