On Tue, Oct 26, 2021 at 4:36 AM Guido van Rossum <gu...@python.org> wrote:
>
> On Mon, Oct 25, 2021 at 10:28 AM Chris Angelico <ros...@gmail.com> wrote:
>>
>> [...] The two options on the table are:
>>
>> 1) Allow references to any value that has been provided in any way
>> 2) Allow references only to parameters to the left
>>
>> Option 2 is a simple SyntaxError on compilation (you won't even get as
>> far as the def statement). Option 1 allows everything all up to the
>> point where you call it, but then might raise UnboundLocalError if you
>> refer to something that wasn't passed.
>
>
> Note that if you were to choose the SyntaxError option, you'd be breaking new 
> ground. Everywhere else in Python, undefined names are runtime errors 
> (NameError or UnboundLocalError).
>

I'm considering this to be more similar to mismatching local and
global usage, or messing up nonlocal names:

>>> def spam():
...     ham
...     global ham
...
  File "<stdin>", line 3
SyntaxError: name 'ham' is used prior to global declaration
>>> def spam():
...     def ham():
...             nonlocal eggs
...
  File "<stdin>", line 3
SyntaxError: no binding for nonlocal 'eggs' found

The problem is the bizarre inconsistencies that can come up, which are
difficult to explain unless you know exactly how everything is
implemented internally. What exactly is the difference between these,
and why should some be legal and others not?

def f1(x=>y + 1, y=2): ...
def f2(x=>y + 1, y=>2): ...
def f3(x=>y + 1, *, y): ...
def f4(x=>y + 1): y = 2
def f5(x=>y + 1):
    global y
    y = 2

And importantly, do Python core devs agree with less-skilled Python
programmers on the intuitions?

If this should be permitted, there are two plausible semantic meanings
for these kinds of constructs:

1) Arguments are defined left-to-right, each one independently of each other
2) Early-bound arguments and those given values are defined first,
then late-bound arguments

The first option is much easier to explain, but will never give useful
results for out-of-order references (unless it's allowed to refer to
the containing scope or something). The second is closer to the "if x
is None: x = y + 1" equivalent, but is harder to explain.

Two-phase initialization is my second-best preference after rejecting
with SyntaxError, but I would love to see some real-world usage before
opening it up. Once permission is granted, it cannot be revoked, and
it might turn out that one of the other behaviours would have made
more sense.

ChrisA
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/46ZWYA2Q6TQGKTYA5Z5MLPXZLM6ABAH5/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to