问题
The documentation for the Field class of python's standard dataclasses module specifies only:
Its documented attributes are:
- [...]
- type: The type of the field.
To me, it seems to mean that the field will contain the type itself, and not only it's name in the form of a string.
However, it seems that it simply copies the type annotation as is, making it quite useless.
Example:
@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
The problem even occurs systematically when using PEP563 type annotations.
Is this a bug in the dataclasses module? Is this the expected behavior? If so, how do I retrieve a type object given a Field instance?
回答1:
This is deliberate. Resolving type hints at import time is expensive, especially when from __future__ import annotations
has been used to disable resolving them in the first place.
Initially, the addition of the PEP 563 to Python 3.7 broke dataclasses when you used the from __future__ import annotations
switch and included ClassVar or InitVar type annotations for fields; these would not be resolved at this point and remained a string. This was already a problem before PEP 563 if you explicitly used strings, see dataclasses issue #92. This became a Python bug, #33453, once dataclasses made it into Python 3.7 proper.
The 'parent' project, attrs
, which inspired dataclasses
, also had this issue to solve. There, Łukasz Langa (co-author of most of the type hinting peps, including PEP 563), states:
OK, so I tried the above and it seems it's a nuclear option since it forces all annotations to be evaluated. This is what I wanted to avoid with
from __future__ import annotations
.
and in the discussion on the pull request that fixed issue 33453, Eric Smith, author of dataclasses
, stated:
I've been researching doing just that. I think @ambv's point is that it introduces a performance hit due to calling eval on every field, while the point of string annotations is to remove a performance hit.
Moreover, there were other problems; you can't evaluate all type hints at import time, not when they use forward references:
In addition to the performance issue, in the following case (without a
__future__
statement and without dataclasses), I get an error onget_type_hints()
becauseC
is undefined whenget_type_hints()
is called. This is python/typing#508. Notice that whereget_type_hints()
is called in this example is exactly where@dataclass
is going to run and would need to call the stripped downget_type_hints()
.
So in the end, all that dataclasses
does is do is apply string heuristics to the annotations, and will not load them for you.
To retrieve the type, just use get_type_hints()
on the class itself, and us the field .name
attribute as the key into the result:
resolved = typing.get_type_hints(C)
f = dataclasses.fields(C)[0]
ftype = resolved[f.name]
来源:https://stackoverflow.com/questions/55937859/dataclasses-field-doesnt-resolve-type-annotation-to-actual-type