
Short version of my more detailed answer below: While my rationale is different from Barry's, I've convinced myself that the right thing to do for Python 3.8 is to remove the new TargetScopeError and have these cases all just raise SyntaxError. I do still see potential value in a new "AssignmentScopeError" subclass, but it would apply to more than just these new exceptions, and can be considered on a more leisurely basis for Python 3.9. On Fri, 9 Aug 2019 at 03:07, Barry Warsaw <barry@python.org> wrote:
bpo-37757: https://bugs.python.org/issue37757
This issue describes some corner cases in PEP 572 (assignment expressions) syntax that haven’t been implemented yet. The PEP currently says:
"The two invalid cases listed above raise TargetScopeError, a new subclass of SyntaxError (with the same signature).”
The PEP doesn’t really go into the rationale for why a new exception is being defined, and in the issue I’ve argued that we should just raise SyntaxError in those cases. To me, “TargetScopeError” is pretty obscure and doesn’t give users an obvious clue as to what’s going wrong, without searching the interwebs.
Nick argues (apologies if I’m misrepresenting you!):
"I believe our main motivation for separating it out was the fact that even though TargetScopeError is a compile-time error, the affected code is syntactically fine - there are just issues with unambiguously inferring the intended read/write location for the affected target names. (Subclassing SyntaxError is then a pragmatic concession to the fact that "SyntaxError" also de facto means "CompilationError”)”
This accurately conveys what I wrote on the PR and issue, but what I wrote there didn't capture the full background for when TargetScopeError gets raised. The main motivating case that led to the new exception being defined is the one that was already implemented as part of the initial PR adding assignment expressions: the fact we can't readily make PEP 572's parent local scoping for comprehensions work when that parent scope is a class scope. Hence, the TargetScopeError raised in this case: >>> class C: ... [x := 10 for i in range(5)] ... File "<stdin>", line 2 TargetScopeError: named expression within a comprehension cannot be used in a class body Syntactically, the individual pieces of this code are perfectly fine - the problem is that the calculated target for "x" would be in the class body, and there isn't currently a way for the compiler to make that name accessible both in the class scope and in the comprehension body. (We're only able to make zero-arg super work because we don't need to make `__class__` accessible while the class is executing). The new PR then adds the additional checks to disallow the cases where we don't want to enshrine "What CPython's current implementation handles this code" as "The way this code must behave in all Python implementations": >>> [i := 10 for i in range(5)] File "<stdin>", line 1 TargetScopeError: named expression cannot rebind comprehension iteration variable >>> [True for i in range(5) if (j := True) for j in range(5)] File "<stdin>", line 1 TargetScopeError: comprehension inner loop cannot rebind named expression target >>> [True for i in (iterable := range(5))] File "<stdin>", line 1 TargetScopeError: named expression cannot be used in comprehension iterable expression I agree that it's a problem that "Assignment" doesn't appear anywhere in the exception name - if we're going to have a specific name for this, then something like "AssignmentScopeError" would be better. The main counterargument to this approach would be that other similar scoping issues currently just raise SyntaxError: >>> def f(x): global x ... File "<stdin>", line 1 SyntaxError: name 'x' is parameter and global >>> def f(x): nonlocal x ... File "<stdin>", line 1 SyntaxError: name 'x' is parameter and nonlocal >>> def f(): global x; nonlocal x ... File "<stdin>", line 1 SyntaxError: name 'x' is nonlocal and global >>> def f(): nonlocal x ... File "<stdin>", line 1 SyntaxError: no binding for nonlocal 'x' found (Those also highlight that I should tweak the new name specific binding conflict errors to mention the variable name) With a revised exception name though, I think even those existing errors would be improved by switching them over to the subclass: >>> def f(x): global x ... File "<stdin>", line 1 AssignmentScopeError: name 'x' is parameter and global >>> def f(x): nonlocal x ... File "<stdin>", line 1 AssignmentScopeError: name 'x' is parameter and nonlocal >>> def f(): global x; nonlocal x ... File "<stdin>", line 1 AssignmentScopeError: name 'x' is nonlocal and global >>> def f(): nonlocal x ... File "<stdin>", line 1 AssignmentScopeError: no binding for nonlocal 'x' found However, a change like that would make the most sense when considered independently of the specific case of assignment expressions - instead, we would want to ask "What kinds of exceptions does the symbol table analysis pass raise?", and then consider whether it might make sense to define subclasses of syntax error for them. Given the naming issue, and the fact that a potential new SyntaxError subclass would be relevant for more than just the new PEP 572 exceptions, I think the right near term approach is to go with the generic SyntaxError as Barry suggests. I'll update my PRs accordingly. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia