classification
Title: Walrus comprehension rebind checking behavior
Type: behavior Stage:
Components: Versions: Python 3.10, Python 3.9, Python 3.8
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: emilyemorehouse, gousaiyang, gvanrossum
Priority: normal Keywords:

Created on 2021-02-21 01:20 by gousaiyang, last changed 2021-02-27 05:46 by gvanrossum.

Messages (2)
msg387433 - (view) Author: Saiyang Gou (gousaiyang) * Date: 2021-02-21 01:20
# test

PEP 572 disallows walrus use cases such as `[(i := 1) for i in [1]]`, because `for i` implies that `i` is local to the comprehension but `(i := 1)` implies that `i` is "exported", which is a contradiction. However, I noticed the following behavior both in 3.8 and 3.9:

>>> [(a := 1) for a, (*b, c[d+e::f(g)], h.i) in [1]]
  File "<stdin>", line 1
SyntaxError: assignment expression cannot rebind comprehension iteration variable 'a'
>>> [(b := 1) for a, (*b, c[d+e::f(g)], h.i) in [1]]
  File "<stdin>", line 1
SyntaxError: assignment expression cannot rebind comprehension iteration variable 'b'
>>> [(c := 1) for a, (*b, c[d+e::f(g)], h.i) in [1]]
  File "<stdin>", line 1
SyntaxError: assignment expression cannot rebind comprehension iteration variable 'c'
>>> [(d := 1) for a, (*b, c[d+e::f(g)], h.i) in [1]]
  File "<stdin>", line 1
SyntaxError: assignment expression cannot rebind comprehension iteration variable 'd'
>>> [(e := 1) for a, (*b, c[d+e::f(g)], h.i) in [1]]
  File "<stdin>", line 1
SyntaxError: assignment expression cannot rebind comprehension iteration variable 'e'
>>> [(f := 1) for a, (*b, c[d+e::f(g)], h.i) in [1]]
  File "<stdin>", line 1
SyntaxError: assignment expression cannot rebind comprehension iteration variable 'f'
>>> [(g := 1) for a, (*b, c[d+e::f(g)], h.i) in [1]]
  File "<stdin>", line 1
SyntaxError: assignment expression cannot rebind comprehension iteration variable 'g'
>>> [(h := 1) for a, (*b, c[d+e::f(g)], h.i) in [1]]
  File "<stdin>", line 1
SyntaxError: assignment expression cannot rebind comprehension iteration variable 'h'
>>> [(i := 1) for a, (*b, c[d+e::f(g)], h.i) in [1]]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <listcomp>
TypeError: cannot unpack non-iterable int object

Among all of these assignment expressions, only the assignment to `i` (attribute name) is allowed. However, in my understanding, only `a` and `b` should be disallowed for assignment. This comprehension example only creates two new variables, `a` and `b`, which are local to the comprehension. Assignment expressions assigning to `c`, `d`, `e`, `f`, `g` and `h` should be allowed. `c` and `h` are already in the outer scope. `d`, `e`, `f` and `g` are just names inside the expression in the subscript part. They are not "comprehension iteration variables" and not local to the comprehension.

The same behavior is also observed when detecting inner loop variable rebinding outer loop assignment expression targets:

>>> [i for i in range(5) if (j := 0) for k[j + 1] in range(5)]
  File "<stdin>", line 1
SyntaxError: comprehension inner loop cannot rebind assignment expression target 'j'
msg387768 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2021-02-27 05:46
I'd like Emily to have a look at that.
History
Date User Action Args
2021-02-27 05:46:20gvanrossumsetnosy: + emilyemorehouse
messages: + msg387768
2021-02-27 02:36:30terry.reedysetnosy: + gvanrossum
2021-02-21 01:20:04gousaiyangcreate