0

考虑以下类:

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解释器而不被视为默认值?我可以在自己的函数中复制这种行为吗?

4

1 回答 1

2

不是“@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及其Fields 的逻辑。例如,这意味着不能创建“具有默认值但不被视为默认值的字段”——这取决于人们如何接近它,dataclass要么忽略它,要么在准备实际类时仍然引发错误。

于 2021-11-10T11:38:38.670 回答