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/

Reply via email to