0

Why can I use the same variable names as loop indices in nested list comprehensions?

Let's create a 5x7 matrix of zeros:

dim1 = 5

dim2 = 7

m = [[0 for _ in range(dim2)] for _ in range(dim1)]

I expect the inner comprehension to overwrite the value of variable _. Why doesn't it?

Just to be clear, the code below is supposed to be an equivalent for-loop representation. It only works as reproduced, i.e. with i and j, not with i and i as loop indices. So why does the comprehension work then?

dim1 = 5

dim2 = 7

m1 = []

for i in range(dim1):
    m1.append([])
    for j in range(dim2):
        m1[i].append(0)
khelwood
  • 55,782
  • 14
  • 81
  • 108
  • 3
    Um .. it does "overwrite the value of variable _", but in this case it does not matter, because the content of the variable has no influence on the return values of the range method(s), plus you're never using the value of \_ anyway. – Mike Scotty Feb 11 '19 at 12:52
  • Using an underscore as variable name is usually like saying: "I don't care about the value of the variable, I just need to put something here to avoid syntax errors". But you are never using the value of `_` so why do you thing it is doing something. – Ralf Feb 11 '19 at 12:52
  • 2
    (1) Why do you assume it does not overwrite it? This code should work either way, since the loop variable is not used in the outer loop, and even if it were, the outer `for` would immediatly rebind it to the expected value. (2) Local names in list comprehension no longer leak to the outer scope since Python 3, see https://stackoverflow.com/questions/4198906/python-list-comprehension-rebind-names-even-after-scope-of-comprehension-is-thi – mkrieger1 Feb 11 '19 at 12:52
  • Because if we write equivalent for-loops it does not work, as per what we expect: dim1 = 5 dim2 = 7 m1 = [] for i in range(dim1): m1.append([]) for i in range(dim2): m1[i].append(0) The above will only work if the inner and outer loop indices have different names. – Peter Yatsyshin Feb 11 '19 at 12:56

2 Answers2

2

The variable is overwritten, you can see it here:

for _ in range(dim1):
    print (_)
    for _ in range(dim2):
        print (_)

Output, below. However, as you dont use the variable, it doesnt matter what value it takes.

0
0
1
2
3
4
5
6
1
0
1
2
3
4
5
6
2
0
1
2
3
4
5
6
3
0
1
2
3
4
5
6
4
0
1
2
3
4
5
6
Rolando cq
  • 588
  • 4
  • 13
1
m = [[0 for _ in range(dim2)] for _ in range(dim1)]

… the code below is supposed to be an equivalent for-loop representation …

m1 = []
for i in range(dim1):
    m1.append([])
    for i in range(dim2):
        m1[i].append(0)

That is not the equivalent nested for loop. That would be:

m1 = []
for i in range(dim1):
    t = []
    for i in range(dim2):
        t.append(0)
    m1.append(t)

i.e., i is never used and it doesn't matter whether it is overwritten.

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
  • So for-loop must have its own scope then. Because we can also do this dim1 = 5 m1 = [] for i in range(dim1): t = [] for i in range(i): #inside this loop the outer i is not accessible t.append(0) print(i) m1.append(t) – Peter Yatsyshin Feb 11 '19 at 13:22