Python 3 2-D list initialization breaks in Python 2

Question:

I’m trying to initialize a 2-D list using list comprehensions, but I’m seeing different results in Python 2 vs. Python 3 and I have no idea why. Sample code (the import is just so I can use v3 print statements in v2):

from __future__ import print_function
ROW = 3
COL = 3

myList = [0 for i in range(ROW)]
#print('myList1 =', myList, 'len =', len(myList))
      
for i in range(len(myList)):
    #print('i =', i)
    myList[i] = [-1 for i in range(COL)]

#myList[0] = [-1 for i in range(COL)]

print('myList2 =', myList)

Python 3 output: myList2 = [[-1, -1, -1], [-1, -1, -1], [-1, -1, -1]]

Python 2 output: myList2 = [0, 0, [-1, -1, -1]]

The Python 3 behavior is what I would expect, and the commented out print statements are what I used to confirm that everything between the two up until the myList[i] assignment is the same. If I manually do, e.g., myList[0] =... outside of the for loop it updates that element as expected. What am I missing here?

Asked By: jml

||

Answers:

You are using i twice within the same for loop, once in the list-comprehension and once as a run variable for the outer for-loop. As detailed in this post, variables used in a list comprehension "leak" into the surrounding scope in python 2x. So your for loop processes like this:

  1. Set i=0, from the for loop:
  • List comprehension generates list of -1‘s and sets i=2

  • myList[i] = is actually myList[2] =

  1. Set i=1, from the for loop:
  • List comprehension generates list of -1‘s and sets i=2

  • myList[i] = is actually myList[2] =

  1. Set i=2, from the for loop:
  • List comprehension generates list of -1‘s and sets i=2

  • myList[i] = is actually myList[2] =

Which generates the list [0, 0, [-1, -1, -1]], because we only ever changed myList[2]

The simplest fix is to use different variables, i.e j in one place:

from __future__ import print_function

ROW = 3
COL = 3

myList = [0 for i in range(ROW)]

for i in range(len(myList)):
    #Use j for the list comprehension
    myList[i] = [-1 for j in range(COL)]

print('myList2 =', myList)
Answered By: FlyingTeller
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.