What is the utility of a type annotation when the thing it refers to cannot
exist?

Deferred annotation lookups are intended to be something that analysis time
can make sense of but can always have no useful meaning at runtime.

No nesting required:

```
from __future__ import annotations
Class X:
  ...

def foo(hi: X):
  ...

del X
```

Now try analyzing foo at runtime...  I assume "Boom" with that NameError
again?  (*On a phone, can't try it now)*

I believe this isn't a problem get_type_hints() can ever solve.

Code that does this isn't what I'd call "reasonably" structured for use
with type hints.

If anything, type checkers should try to warn about it?

-gps

On Tue, Dec 8, 2020, 7:03 PM Paul Bryan <pbr...@anode.ca> wrote:

> Let's try an example that static type checkers should have no problem with:
>
> Python 3.9.0 (default, Oct  7 2020, 23:09:01)
>
> [GCC 10.2.0] on linux
>
> Type "help", "copyright", "credits" or "license" for more information.
>
> >>> from __future__ import annotations
>
> >>>
>
> >>> def make_a_class():
>
> ...     class A:
>
> ...         def get_b(self) -> B:
>
> ...             return B()
>
> ...     class B:
>
> ...         def get_a(self) -> A:
>
> ...             return A()
>
> ...     return A
>
> ...
>
> >>> A = make_a_class()
>
> >>> a = A()
>
> >>>
>
> >>> import typing
>
> >>> typing.get_type_hints(a.get_b)
>
> Traceback (most recent call last):
>
>   File "<stdin>", line 1, in <module>
>
>   File "/usr/lib/python3.9/typing.py", line 1386, in get_type_hints
>
>     value = _eval_type(value, globalns, localns)
>
>   File "/usr/lib/python3.9/typing.py", line 254, in _eval_type
>
>     return t._evaluate(globalns, localns, recursive_guard)
>
>   File "/usr/lib/python3.9/typing.py", line 493, in _evaluate
>
>     eval(self.__forward_code__, globalns, localns),
>
>   File "<string>", line 1, in <module>
>
> NameError: name 'B' is not defined
>
> >>>
>
>
>
>
> On Tue, 2020-12-08 at 18:48 -0800, Guido van Rossum wrote:
>
> Yeah, static type checkers won't like it regardless.
>
> On Tue, Dec 8, 2020 at 6:39 PM Paul Bryan <pbr...@anode.ca> wrote:
>
> It appears that when from future import __annotations__, a type hint
> annotation derived from a closure loses scope.
>
> Simplistic example:
>
> Python 3.9.0 (default, Oct  7 2020, 23:09:01)
>
> [GCC 10.2.0] on linux
>
> Type "help", "copyright", "credits" or "license" for more information.
>
> >>> def make_a_class(data_type):
>
> ...     class Foo:
>
> ...         def put_data(self, data: data_type):
>
> ...             self.data = data
>
> ...     return Foo
>
> ...
>
> >>> import typing
>
> >>> foo = make_a_class(str)()
>
> >>> typing.get_type_hints(foo.put_data)
>
> {'data': <class 'str'>}
>
> >>>
>
>
> If I add a single import to the top, it breaks:
>
> Python 3.9.0 (default, Oct  7 2020, 23:09:01)
>
> [GCC 10.2.0] on linux
>
> Type "help", "copyright", "credits" or "license" for more information.
>
> *>>> from __future__ import annotations  # added this line*
>
> >>> def make_a_class(data_type):
>
> ...     class Foo:
>
> ...         def put_data(self, data: data_type):
>
> ...             self.data = data
>
> ...     return Foo
>
> ...
>
> >>> import typing
>
> >>> foo = make_a_class(str)()
>
> >>> typing.get_type_hints(foo.put_data)
>
> Traceback (most recent call last):
>
>   File "<stdin>", line 1, in <module>
>
>   File "/usr/lib/python3.9/typing.py", line 1386, in get_type_hints
>
>     value = _eval_type(value, globalns, localns)
>
>   File "/usr/lib/python3.9/typing.py", line 254, in _eval_type
>
>     return t._evaluate(globalns, localns, recursive_guard)
>
>   File "/usr/lib/python3.9/typing.py", line 493, in _evaluate
>
>     eval(self.__forward_code__, globalns, localns),
>
>   File "<string>", line 1, in <module>
>
> NameError: name 'data_type' is not defined
>
> >>>
>
>
> I don't see how I can supply the closure scope as localns to
> get_type_hints. Any suggestions? Is constructing a
> (dynamically-type-annotated) class in a function like this an anti-pattern?
>
> _______________________________________________
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/5RK6VXF263F5I4CU7FUMOGOYN2UQG73Q/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
>
>
> _______________________________________________
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/NRH4HBD36WDIP4WR2L4TLTOYMQL2NUFV/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
>
> _______________________________________________
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/6P5GFROAVAYXU3DTELZRHHRCDRYUEWCG/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/VX2LCY436LC4VTMGFXMEVK5UQHZSQQNC/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to