[Python-Dev] Postponed annotations break inspection of dataclasses

Eric V. Smith eric at trueblade.com
Sat Sep 22 14:29:21 EDT 2018

On 9/22/2018 12:41 PM, Guido van Rossum wrote:
> This is a good catch -- thanks for bringing it up. I'm adding Eric Smith 
> (author of dataclasses) and Ivan Levkivskyi (co-author of typing) as 
> well as Łukasz Langa (author of PEP 563) to the thread to see if they 
> have further insights.

I don't see Ivan and Łukasz cc'd, so I'm adding them here.

> Personally I don't think it's feasible to change PEP 563 to use lambdas 
> (if it were even advisable, which would be a long discussion), but I do 
> think we might be able to make small improvements to the dataclasses 
> and/or typing modules to make sure your use case works.
> Probably a bugs.python.org <http://bugs.python.org> issue is a better 
> place to dive into the details than python-dev.

Agreed that opening a bug would be good.

And then I'll ruin that suggestion by answering here, too:

I think this problem is endemic to get_type_hints(). I've never 
understood how you're supposed to use the globals and locals arguments 
to it, but this works:

print(get_type_hints(Bar.__init__, globals()))

as does:

print(get_type_hints(Bar.__init__, Bar.__module__))

But that seems like you'd have to know a lot about how a class were 
declared in order to call get_type_hints on it. I'm not sure __module__ 
is always correct (but again, I haven't really thought about it).

The docs for get_type_hints() says: "In addition, forward references 
encoded as string literals are handled by evaluating them in globals and 
locals namespaces."

Every once in a while someone will bring up the idea of delayed 
evaluation, and the answer is always "use a lambda". If we ever wanted 
to do something more with delayed evaluation, this is a good use case 
for it.


> Thanks again,
> --Guido (top-poster in chief)
> On Sat, Sep 22, 2018 at 8:32 AM David Hagen <david at drhagen.com 
> <mailto:david at drhagen.com>> wrote:
>     The new postponed annotations have an unexpected interaction with
>     dataclasses. Namely, you cannot get the type hints of any of the
>     data classes methods.
>     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 know why this is happening. The `__init__` method is defined in
>     the `dataclasses` module 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 know that the use of lambdas to implement PEP 563 was rejected for
>     performance reasons. I could be wrong, but I think this was
>     motivated by variable annotations because the lambda would have to
>     be constructed each time the function body ran. I was wondering if I
>     could motivate storing the annotations as lambdas in class bodies
>     and function signatures, in which the environment is already being
>     captured and is code that usually only runs once.
>     _______________________________________________
>     Python-Dev mailing list
>     Python-Dev at python.org <mailto:Python-Dev at python.org>
>     https://mail.python.org/mailman/listinfo/python-dev
>     Unsubscribe:
>     https://mail.python.org/mailman/options/python-dev/guido%40python.org
> -- 
> --Guido van Rossum (python.org/~guido <http://python.org/%7Eguido>)
> _______________________________________________
> Python-Dev mailing list
> Python-Dev at python.org
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: https://mail.python.org/mailman/options/python-dev/eric%2Ba-python-dev%40trueblade.com

More information about the Python-Dev mailing list