Дан*_*сов 6 python python-3.x mypy python-typing
dataclass假设你想像这样包装装饰器:
from dataclasses import dataclass
def something_else(klass):
return klass
def my_dataclass(klass):
return something_else(dataclass(klass))
Run Code Online (Sandbox Code Playgroud)
应该如何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)
Run Code Online (Sandbox Code Playgroud)
在PEP 681之前没有可行的方法来做到这一点。
\nAdataclass描述的不是类型而是转换。其实际效果无法通过 Python 的类型系统 \xe2\x80\x93 来表达,它由MyPy 插件@dataclass处理,该插件检查代码,而不仅仅是类型。这是在特定装饰器上触发的,而不了解它们的实现。
dataclass_makers: Final = {\n \'dataclass\',\n \'dataclasses.dataclass\',\n}\nRun Code Online (Sandbox Code Playgroud)\n虽然可以提供自定义 MyPy 插件,但这通常超出了大多数项目的范围。PEP 681 (Python 3.11) 添加了一个通用的“此装饰器的行为类似于@dataclass”标记,可用于从注释到字段的所有转换器。
PEP 681 可通过typing_extensions.
对于纯类型替代方案,定义自定义装饰器以获取数据类并修改它。数据类可以通过其字段来标识__dataclass_fields__。
from typing import Protocol, Any, TypeVar, Type\nimport dataclasses\n\nclass DataClass(Protocol):\n __dataclass_fields__: dict[str, Any]\n\nDC = TypeVar("DC", bound=DataClass)\n\ndef my_dataclass(klass: Type[DC]) -> Type[DC]:\n ...\nRun Code Online (Sandbox Code Playgroud)\n这使得类型检查器能够理解并验证dataclass是否需要一个类。
@my_dataclass\n@dataclass\nclass TestB:\n a: int\n b: str\n\nTestB(0, "") # note: Revealed type is "so_test.TestB"\n\n@my_dataclass\nclass TestC: # error: Value of type variable "DC" of "my_dataclass" cannot be "TestC"\n a: int\n b: str\nRun Code Online (Sandbox Code Playgroud)\nPEP 681装饰器是其他dataclass_transform装饰器的标记,以表明它们的行为“相似” 。为了匹配 的行为,必须使用来指示字段以相同的方式表示。@dataclass@dataclassfield_specifiers
from typing import dataclass_transform, TypeVar, Type\nimport dataclasses\n\nT = TypeVar("T")\n\n@dataclass_transform(\n field_specifiers=(dataclasses.Field, dataclasses.field),\n)\ndef my_dataclass(klass: Type[T]) -> Type[T]:\n return something_else(dataclasses.dataclass(klass))\nRun Code Online (Sandbox Code Playgroud)\n自定义数据类装饰器可以将所有关键字视为@dataclass。dataclass_transform可以用来标记它们各自的默认值,即使装饰器本身不接受作为关键字。