假设你想像这样包装
dataclass
装饰器:
from dataclasses import dataclass
def something_else(klass):
return klass
def my_dataclass(klass):
return something_else(dataclass(klass))
应该如何注释
my_dataclass
和/或 something_else
以指示返回类型是数据类?
请参阅以下示例,了解内置 @dataclass
如何工作,但自定义 @my_dataclass
则不然:
@dataclass
class TestA:
a: int
b: str
TestA(0, "") # fine
@my_dataclass
class TestB:
a: int
b: str
TestB(0, "") # error: Too many arguments for "TestB" (from mypy)
在 PEP 681 之前没有可行的方法来做到这一点。
A
dataclass
描述的不是类型而是转换。它的实际效果无法用 Python 的类型系统来表达 - @dataclass
由 MyPy Plugin 处理,它检查代码,而不仅仅是类型。这是在不了解其实现的情况下在特定装饰器上触发的。
dataclass_makers: Final = {
'dataclass',
'dataclasses.dataclass',
}
虽然可以提供自定义 MyPy 插件,但这通常超出了大多数项目的范围。 PEP 681 (Python 3.11) 添加了一个通用的“此装饰器的行为类似于 @dataclass
”标记,可用于从注释到字段的所有转换器。PEP 681 可通过 适用于早期的 Python 版本。 强制执行数据类
获取数据类并修改它。数据类可以通过其 __dataclass_fields__
字段来标识。
from typing import Protocol, Any, TypeVar, Type
import dataclasses
class DataClass(Protocol):
__dataclass_fields__: dict[str, Any]
DC = TypeVar("DC", bound=DataClass)
def my_dataclass(klass: Type[DC]) -> Type[DC]:
...
这使得类型检查器能够理解并验证是否需要一个dataclass
类。
@my_dataclass
@dataclass
class TestB:
a: int
b: str
TestB(0, "") # note: Revealed type is "so_test.TestB"
@my_dataclass
class TestC: # error: Value of type variable "DC" of "my_dataclass" cannot be "TestC"
a: int
b: str
自定义类似数据类的装饰器dataclass_transform
装饰器是other 装饰器的标记,以表明它们的行为“像”
@dataclass
。为了匹配
@dataclass
的行为,必须使用
field_specifiers
来指示字段以相同的方式表示。
from typing import dataclass_transform, TypeVar, Type
import dataclasses
T = TypeVar("T")
@dataclass_transform(
field_specifiers=(dataclasses.Field, dataclasses.field),
)
def my_dataclass(klass: Type[T]) -> Type[T]:
return something_else(dataclasses.dataclass(klass))
自定义数据类装饰器可以将所有关键字作为@dataclass
。
dataclass_transform
可用于标记它们各自的默认值,即使装饰器本身不接受作为关键字也是如此。
metaclass decorator
及其魔力 关于
__init__
,但不明白
dataclass function
:
@dataclass
class Test:
a: int
# Mypy: Revealed type is "def (self: Test, a: builtins.int)"
reveal_type(Test.__init__)
class Test2:
a: int
#Mypy: Revealed type is "def (self: builtins.object)"
reveal_type(dataclass(Test2).__init__)
如您所见,__init__
的
Test2
方法不接受任何参数。