If you never examine __annotations__, then you can refer to symbols that
are never defined and nothing bad happens. It's just like writing a
function that refers to undefined symbols, then never calling that function.
If you examine __annotations__, and the annotations refer to values that
aren't defined, the evaluation fails. This too works like you'd expect:
the __co_annotation__ function raises NameError. So your IPython use
case would raise a NameError.
Note that the code is deliberately written to allow you to fix the name
errors and try again. (The __co_annotations__ attribute is only cleared
if calling it succeeds and it returns a legal value.) So, if you
examine an annotation in IPython, and it fails with a NameError, you
could import the missing module--or otherwise do what is needed to fix
the problem--and try again.
If your imports are complicated, you could always hide them in a
function. I just tried this and it seems to work fine:
def my_imports():
global other_mod
import other_mod
So, you could put all your imports in such a function, run it from
inside a "if typing.TYPE_CHECKING" block, and you'd have a convenient
way of doing all your imports from inside IPython too.
One final note: with PEP 649, you can still use strings as annotations
if you prefer. You just have to write them as strings manually. So the
IPython use case could continue to work correctly that way. I realize
that this itself causes minor problems--it means no syntax checking is
done on the annotation, and it causes a little extra work for the
user--but I assume this is a rare use case and most users won't need to
bother.
Cheers,
//arry/
//
On 1/16/21 11:43 PM, Inada Naoki wrote:
This PEP doesn't cover about what happened when __co_annotation__()
failed (e.g. NameError).
Forward reference is a major reason, but not a only reason for using
string annotation. There are two other reasons:
* Avoid importing heavy module.
* Avoid circular imports.
In these cases, this pattern is used:
```
from __future__ import annotations
import typing
from dataclasses import dataclass
if typing.TYPE_CHECKING:
import other_mod # do not want to import actually
@dataclass
class Foo:
a: other_mod.spam
b: other_mod.ham
def fun(a: other_mod.spam, b: other_mod.ham) -> None: ...
```
Of course, mypy works well with string annotation because it is static checker.
IPython shows signature well too:
```
In [3]: sample.Foo?
Init signature: sample.Foo(a: 'other_mod.spam', b: 'other_mod.ham') -> None
Docstring: Foo(a: 'other_mod.spam', b: 'other_mod.ham')
```
PEP 563 works fine in this scenario. How PEP 649 works?
Regards,
_______________________________________________
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/YMK24F6FWOTKAUO7ISJYMFYLJQPDWMO6/
Code of Conduct: http://python.org/psf/codeofconduct/