__annotations__ 不 return 来自父数据类的字段

__annotations__ doesn't return fields from a parent dataclass

我正在了解 dataclass,但我无法理解为什么 __annotations__ 不提供来自父 class 的字段。请参阅以下示例:

import dataclasses as dc

@dc.dataclass
class B:
    a: int

B.__annotations__
# returns {'a': int}

C = dc.make_dataclass("c", fields=["w"], bases=(B,))
C.__annotations__
# returns {'w': 'typing.Any'} (without a)

__annotations__ 不会给你父 class 的类型注释,因为它应该只包含在 class 自身中定义的注释。有一个特定的函数 returns 一个 class 的所有注释,包括其父项的注释,称为 typing.get_type_hints:

This is often the same as obj.__annotations__. [...] For a class C, return a dictionary constructed by merging all the __annotations__ along C.__mro__ in reverse order.

在您的特定示例中使用它时要记住的一件事是数据classes使用大量黑魔法来构造classes,并且它会在查找所有类型时中断如果某些字段在 make_dataclass 定义中未键入则提示(作为错误 here 提交):

import dataclasses as dc
from typing import Any, get_type_hints

@dc.dataclass
class B:
    a: int

get_type_hints(B)
# returns {'a': <class 'int'>}

# fields=["w"] should be equivalent, but get_type_hints doesn't like it. Bug, maybe?
C = dc.make_dataclass("C", fields=[("w", Any)], bases=(B,))

typing.get_type_hints(C)
# returns {'a': <class 'int'>, 'w': typing.Any}

但是正如 user2357112 指出的那样,最好建议您使用 dataclasses.fields 函数,该函数 returns dataclass 装饰器根据数据class 及其基础。这是您在分析数据时通常想要使用的classes,它包含您需要的所有信息以及更多信息。

此外,它与您最初使用的 make_dataclass 中字段的 shorthand 定义一起工作,并清除伪字段:

dc.fields(D)
# returns a tuple of 
Field(name='a',type=<class 'int'>,default=<dataclasses._MISSING_TYPE object at 0x7f103d9985c0>,default_factory=<dataclasses._MISSING_TYPE object at 0x7f103d9985c0>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),_field_type=_FIELD)
# and
Field(name='w',type=typing.Any,default=<dataclasses._MISSING_TYPE object at 0x7f103d9985c0>,default_factory=<dataclasses._MISSING_TYPE object at 0x7f103d9985c0>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),_field_type=_FIELD)