8

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?

4

1 回答 1

1

When reported to the Python mailing list, this was considered a "good catch" by the BDFL. According to the issue, this has been fixed. The pull request for the fix was merged and backported. It works as expected starting in Python 3.7.6 and Python 3.8.1.

于 2018-10-24T12:43:56.873 回答