Hi Larry,
On 4/12/21, 6:57 PM, "Larry Hastings" <[email protected] on behalf of
[email protected]> wrote:
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.
Normally in Python, if you reference a symbol in a function definition line,
the symbol must be defined at that point in module execution. Forward
references are not permitted, and will raise `NameError`.
And yet you have implemented PEP 649, whose entire raison d'être is to
implement a "special case" to "break the rules" by delaying evaluation of
annotations such that a type annotation, unlike any other expression in the
function definition line, may include forward reference names which will not be
defined until later in the module.
The use case for `if TYPE_CHECKING` imports is effectively the same. They are
just forward references to names in other modules which can't be imported
eagerly, because e.g. it would cause a cycle. Those who have used type
annotations in earnest are likely to confirm that such inter-module forward
references are just as necessary as intra-module forward references for the
usability of type annotations.
So it doesn't seem that we have here is a firm stand on principle of the Zen,
it appears to rather be a disagreement about exactly where to draw the line on
the "special case" that we all already seem to agree is needed.
The Zen argument seems to be a bit of a circular one: I have defined PEP 649
semantics in precisely this way, therefore code that works with PEP 649 does
not have an error, and code that does not work with PEP 649 "has an error"
which must be surfaced!
With PEP 563, although `get_type_hints()` cannot natively resolve inter-module
forward references and raises `NameError`, it is possible to work around this
by supplying a globals dict to `get_type_hints()` that has been augmented with
those forward-referenced names. Under the current version of PEP 649, it
becomes impossible to get access to such type annotations at runtime at all,
without reverting to manually stringifying the annotation and then using
something like `get_type_hints()`. So for users of type annotations who need
`if TYPE_CHECKING` (which I think is most users of type annotations), the
best-case overall effect of PEP 649 will be that a) some type annotations have
to go back to being ugly strings in the source, and b) if type annotation
values are needed at runtime, `get_type_hints()` will still be as necessary as
it ever was.
It is possible for PEP 649 to draw the line differently and support both
intra-module and inter-module forward references in annotations, by doing
something like https://github.com/larryhastings/co_annotations/pull/3 and
replacing unknown names with forward-reference markers, so the annotation
values are still accessible at runtime. This meets the real needs of users of
type annotations better, and gives up none of the benefits of PEP 649.
Carl
_______________________________________________
Python-Dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/DSZFE7XTRK2ESRJDPQPZIDP2I67E76WH/
Code of Conduct: http://python.org/psf/codeofconduct/