python 如何知道 dataclasses.field 函数不是数据类中的默认值?
How does python know that dataclasses.field function is not a default value in a dataclass?
考虑以下 class:
from dataclasses import dataclass
@dataclass
class C:
a: int = 1
b: int
尝试执行此操作会产生 TypeError: non-default argument 'b' follows default argument
现在考虑一下:
from dataclasses import dataclass, field
from dataclasses_json import config
@dataclass
class C:
a: int = field(metadata=config(encoder=lambda x: x, decoder=lambda x: x))
b: int
这执行没有错误。
问题是:field
函数如何“欺骗”python 解释器而不被视为默认值?我可以在我自己的函数中复制这种行为吗?
@dataclass
不是“由解释器解释”,因为解释器不“知道”它必须引发像 TypeError: non-default argument 'b' follows default argument
这样的错误。相反,@dataclass
是检查 class 对象和 explicitly raises the error.
的常规 Python 函数
这种机制的高级描述是 field
returns a Field
object containing the meta-data passed to field
. The @dataclass
code checks if class attribute values are Field
objects,而不是它们是否由 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
请注意,从概念上讲,人们仍然受限于 dataclass
及其 Field
的逻辑。例如,这意味着不能创建“ 具有默认值 但不被视为默认值的字段”——根据处理方式,dataclass
要么忽略它或者在准备实际的 class.
时仍然会引发错误
考虑以下 class:
from dataclasses import dataclass
@dataclass
class C:
a: int = 1
b: int
尝试执行此操作会产生 TypeError: non-default argument 'b' follows default argument
现在考虑一下:
from dataclasses import dataclass, field
from dataclasses_json import config
@dataclass
class C:
a: int = field(metadata=config(encoder=lambda x: x, decoder=lambda x: x))
b: int
这执行没有错误。
问题是:field
函数如何“欺骗”python 解释器而不被视为默认值?我可以在我自己的函数中复制这种行为吗?
@dataclass
不是“由解释器解释”,因为解释器不“知道”它必须引发像 TypeError: non-default argument 'b' follows default argument
这样的错误。相反,@dataclass
是检查 class 对象和 explicitly raises the error.
这种机制的高级描述是 field
returns a Field
object containing the meta-data passed to field
. The @dataclass
code checks if class attribute values are Field
objects,而不是它们是否由 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
请注意,从概念上讲,人们仍然受限于 dataclass
及其 Field
的逻辑。例如,这意味着不能创建“ 具有默认值 但不被视为默认值的字段”——根据处理方式,dataclass
要么忽略它或者在准备实际的 class.