dataclasses.Field不能将类型注释解析为实际类型

时间:2019-05-01 14:30:09

标签: python python-dataclasses

python的标准Field模块的dataclasses类的文档仅指定:

  

其记录的属性为:

     
      
  • [...]
  •   
  • 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类型注释时,该问题甚至会系统地发生。

这是dataclasses模块中的错误吗?这是预期的行为吗?如果是这样,如何在给定Field实例的情况下检索类型对象?

1 个答案:

答案 0 :(得分:2)

这是故意的。在导入时解析类型提示是昂贵的,尤其是当from __future__ import annotations首先被用来禁止解析它们时。

最初,当您使用from __future__ import annotations开关并为字段包括ClassVarInitVar类型注释时,在python 3.7中添加了PEP 563破坏了数据类;这些问题目前仍无法解决,仍然是一个字符串。如果您明确使用字符串,那么在PEP 563之前这已经是一个问题,请参阅dataclasses issue #92。一旦数据类使其成为Python 3.7合适的版本,它就变成了Python bug, #33453

启发了attrsalso had this issue to solve的“父”项目dataclasses。在那里,ŁukaszLanga(大多数提示类型的鼓舞者,包括PEP 563的合著者)说:

  

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

dataclasses的作者埃里克·史密斯(Eric Smith)在discussion on the pull request that fixed issue 33453中说:

  

我一直在研究这样做。我认为@ambv的要点是,由于在每个字段上调用eval,它会导致性能下降,而字符串注释的作用是消除性能下降。

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

  

除了性能问题外,在以下情况下(没有__future__语句,也没有数据类),我在get_type_hints()上遇到了错误,因为当{{1 }} 叫做。这是python/typing#508。请注意,在此示例中,调用C的位置正好是get_type_hints()的运行位置,需要调用简化后的get_type_hints()

最后,@dataclass所做的就是将字符串启发式方法应用于注释,而不会为您加载它们。

要检索类型,只需在类本身上使用get_type_hints(),然后将字段dataclasses属性用作结果键:

get_type_hints()