With PEP 563, from __future__ import annotations
changes type annotations so that they are evaluated lazily, which provides a bunch of benefits like forward references.
However, this seems to play badly with other features, like dataclasses. For example, I have some code that inspects the type parameters of a class's __init__
method. (The real use case is to provide a default serializer for the class, but that is not important here.)
from dataclasses import dataclass
from typing import get_type_hints
class Foo:
pass
@dataclass
class Bar:
foo: Foo
print(get_type_hints(Bar.__init__))
In Python 3.6 and 3.7, this does what is expected; it prints {'foo': <class '__main__.Foo'>, 'return': <class 'NoneType'>}
.
However, if in Python 3.7, I add from __future__ import annotations
, then this fails with an error:
NameError: name 'Foo' is not defined
I think I understand why this is happening. The __init__
method is defined in dataclasses
which does not have the Foo
object in its environment, and the Foo
annotation is being passed to dataclass
and attached to __init__
as the string "Foo"
rather than as the original object Foo
, but get_type_hints
for the new annotations only does a name lookup in the module where __init__
is defined not where the annotation is defined.
I feel like I must be doing something wrong. I am surprised that these two new features play so poorly together. Is there a proper way to inspect the type hints of of an __init__
method so that it works on dataclasses like it does on normal classes?