2

python 标准数据类模块的 Field 类的文档指定

其记录的属性是:

  • [...]
  • type:字段的类型。

对我来说,这似乎意味着该字段将包含类型本身,而不仅仅是字符串形式的名称。

但是,它似乎只是按原样复制类型注释,使其毫无用处。

例子:

@dataclasses.dataclass 
class C: 
    c: 'C'

dataclasses.fields(C)[0].type # This returns the string 'C'
typing.get_type_hints(C)['c'] # This returns the class C, as expected

在使用PEP563类型注释时,甚至会系统地出现该问题。

这是数据类模块中的错误吗?这是预期的行为吗?如果是这样,我如何检索给定 Field 实例的类型对象?

4

1 回答 1

8

这是故意的。在导入时解析类型提示是昂贵的,尤其是from __future__ import annotations在最初用于禁用解析它们时。

最初,在 Python 3.7 中添加 PEP 563 会破坏数据类,当您使用from __future__ import annotations开关并为字段包含ClassVarInitVar键入注释时;这些在这一点上不会得到解决,并且仍然是一个字符串。如果您明确使用字符串,这在 PEP 563 之前已经是一个问题,请参阅数据类问题 #92。一旦数据类进入 Python 3.7,这变成了一个Python 错误,#33453 。

attrs受到启发dataclasses的“父”项目也有这个问题需要解决。在那里,Łukasz Langa(大多数类型提示 peps 的合著者,包括 PEP 563)说:

好的,所以我尝试了上述方法,它似乎是一个核选项,因为它强制评估所有注释。这是我想避免的from __future__ import annotations

讨论修复问题 33453 的拉取请求时,作者 Eric Smithdataclasses表示:

我一直在研究这样做。我认为@ambv 的观点是它引入了由于在每个字段上调用 ​​eval 导致的性能损失,而字符串注释的目的是消除性能损失。

此外,还有其他问题;您不能在导入时评估所有类型提示,而不是在它们使用前向引用时:

除了性能问题之外,在以下情况下(没有__future__语句且没有数据类),我得到一个错误,get_type_hints()因为在调用C时是未定义get_type_hints()的。这是python/typing#508。请注意,get_type_hints()在此示例中调用的位置@dataclass正是要运行的位置,并且需要调用剥离的get_type_hints()

所以最后,dataclasses所做的只是将字符串启发式应用于注释,并且不会为您加载它们。

要检索类型,只需get_type_hints()在类本身上使用,并将字段.name属性作为结果的键:

resolved = typing.get_type_hints(C)
f = dataclasses.fields(C)[0]
ftype = resolved[f.name]
于 2019-05-01T15:04:36.383 回答