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
_______________________________________________
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/F4BZLEQ36MIIBDRUIMNGWCSSE6AMYM5K/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to