如何注释函数生成数据类?

问题描述 投票:0回答:2

假设你想像这样包装

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)
python python-typing mypy
2个回答
8
投票

PEP 681 之前没有可行的方法来做到这一点。

A

dataclass
描述的不是类型而是转换。它的实际效果无法用 Python 的类型系统来表达 -
@dataclass
MyPy Plugin 处理,它检查代码,而不仅仅是类型。这是在不了解其实现的情况下在特定装饰器上触发的。

dataclass_makers: Final = { 'dataclass', 'dataclasses.dataclass', }
虽然可以提供自定义 MyPy 插件,但这通常超出了大多数项目的范围。 PEP 681 (Python 3.11) 添加了一个通用的“此装饰器的行为类似于 

@dataclass

”标记,可用于从注释到字段的所有转换器。

PEP 681 可通过

typing_extensions

 适用于早期的 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
自定义类似数据类的装饰器

PEP 681

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
 可用于标记它们各自的默认值,即使装饰器本身不接受作为关键字也是如此。


0
投票
问题是 mypy 理解

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
方法不接受任何参数。

© www.soinside.com 2019 - 2024. All rights reserved.