On Thu, Oct 21, 2021 at 04:48:28PM -0400, Larry Hastings wrote:
In Python, if you evaluate an undefined name, Python raises a NameError. This is so consistent I'm willing to call it a "rule". Various folks have proposed an exception to this "rule": evaluating an undefined name in an PEP 649 delayed annotation wouldn't raise NameError, instead evaluating to some yet-to-be-determined value (ForwardRef, AnnotationName, etc). I don't think annotations are special enough to "break the rules" in this way.
Can we have a code snippet illustrating that? I think this is what you mean. Please correct me if I have anything wrong. If I have this: from typing import Any def function(arg:Spam) -> Any: ... then we have four sets of (actual or proposed) behaviour: 1. The original, current and standard behaviour is that Spam raises a NameError at function definition time, just as it would in any other context where the name Spam is undefined, e.g. `obj = Spam()`. 2. Under PEP 563 (string annotations), there is no NameError, as the annotations stay as strings until you attempt to explicitly resolve them using eval. Only then would it raise NameError. 3. Under PEP 649 (descriptor annotations), there is no NameError at function definition time, as the code that resolves the name Spam (and Any for that matter) is buried in a descriptor. It is only on inspecting `function.__annotations__` at runtime that the code in the descriptor is run and the name Spam will generate a NameError. 4. Guido would(?) like PEP 649 to be revised so that inspecting the annotations at runtime would not generate a NameError. Since Spam is unresolvable, some sort of proxy or ForwardRef (or maybe just a string?) would have to be returned instead of raising. Am I close? My initial thought was to agree with Larry about special cases, but perhaps we could borrow part of PEP 563 and return a string if the name Spam is unresolvable. Runtime type checkers already have to deal with forward refs that are strings, as this is legal, and always will be: def function(arg:'Spam') -> Any: ... so we're not putting any extra burden on them. And we had already agreed to implicitly use strings for annotations. So if I have understood the options correctly, I like the idea of a hybrid descriptor + stringy annotations solution. - defer evaluation of the annotations using descriptors (PEP 649); - on runtime evaluation, if a name does not resolve, stringify it (as PEP 563 would have done implicitly); - anyone who really wants to force a NameError can eval the string. More practically, folks will more likely delay evaluating the string until Spam has been created/imported and will resolve. -- Steve