On 4/12/21 4:50 PM, Inada Naoki wrote:
PEP 563 solves all problems relating to types not accessible in runtime. There are many reasons users can not get types used in annotations at runtime:
- To avoid circular import
- Types defined only in pyi files
- Optional dependency that is slow to import or hard to install
It only "solves" these problems if you leave the annotation as a string. If PEP 563 is active, but you then use typing.get_type_hints() to examine the actual Python value of the annotation, all of these examples will fail with a NameError. So, in this case, "solves the problem" is a positive way of saying "hides a runtime error".
I don't know what the use cases are for examining type hints at runtime, so I can't speak as to how convenient or inconvenient it is to deal with them strictly as strings. But it seems to me that examining annotations as their actual Python values would be preferable.
This is the most clear point where PEP 563 is better for some users. See this example:
from dataclasses import dataclass if 0: from fakemod import FakeType @dataclass class C: a : FakeType = 0
This works on PEP 563 semantics (Python 3.10a7). User can get stringified annotation.
With stock semantics, it cause NameError when importing so author can notice they need to quote "FakeType".
With PEP 649 semantics, author may not notice this annotation cause error. User can not get any type hints at runtime.
Again, by "works on PEP 563 semantics", you mean "doesn't raise an error". But the code /has/ an error. It's just that it has been hidden by PEP 563 semantics.
I don't agree that changing Python to automatically hide errors is an improvement. As the Zen says: "Errors should never pass silently."
This is really the heart of the debate over PEP 649 vs PEP 563. If you examine an annotation, and it references an undefined symbol, should that throw an error? There is definitely a contingent of people who say "no, that's inconvenient for us". I think it should raise an error. Again from the Zen: "Special cases aren't special enough to break the rules." Annotations are expressions, and if evaluating an expression fails because of an undefined name, it should raise a NameError.
### Type alias
Another PEP 563 benefit is user can see simple type alias. Consider this example.
from typing import * AliasType = Union[List[Dict[Tuple[int, str], Set[int]]], Tuple[str, List[str]]] def f() -> AliasType: pass help(f)
Currently, help() calls `typing.get_type_hints()`. So it shows:
f() -> Union[List[Dict[Tuple[int, str], Set[int]]], Tuple[str, List[str]]]
But with PEP 563 semantics, we can stop evaluating annotations and user can see more readable alias type.
f() -> AliasType
It's a matter of personal opinion whether "AliasType" or the full definition is better here. And it could lead to ambiguity, if the programmer assigns to "AliasType" more than once.
Iif the programmer has a strong opinion that "AliasType" is better, they could use an annotation of 'AliasType'--in quotes. Although I haven't seen the topic discussed specifically, I assume that the static typing analysis tools will continue to support manually stringized annotations even if PEP 649 is accepted.
Either way, this hypothetical feature might be "nice-to-have", but I don't think it's very important. I would certainly forego this behavior in favor of accepting PEP 649.