64

I'm getting mad with list indexes, and can't explain what I'm doing wrong.

I have this piece of code in which I want to create a list of lists, each one containing values of the same circuit parameter (voltage, current etc..) that I'm reading from a csv file that looks like this:

Sample, V1, I1, V2, I2
0, 3, 0.01, 3, 0.02
1, 3, 0.01, 3, 0.03

And so on. What I want is to create a list that for example contains V1 and I1 (but I want to chose interactively) in the form [[V1], [I1]], so:

[[3,3], [0.01, 0.01]]

The code that I'm using is this:

plot_data = [[]]*len(positions)    
for row in reader:
    for place in range(len(positions)):
        value = float(row[positions[place]])
        plot_data[place].append(value)

plot_data is the list that contains all the values, while positions is a list with the indexes of the columns that I want to copy from the .csv file. The problem is that if I try the commands in the shell, seems to work, but if I run the script instead of appending each value to the proper sub-list, it appends all values to all lists, so I obtain 2 (or more) identical lists.

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
clabacchio
  • 1,047
  • 1
  • 17
  • 28

2 Answers2

142

Python lists are mutable objects and here:

plot_data = [[]] * len(positions) 

you are repeating the same list len(positions) times.

>>> plot_data = [[]] * 3
>>> plot_data
[[], [], []]
>>> plot_data[0].append(1)
>>> plot_data
[[1], [1], [1]]
>>> 

Each list in your list is a reference to the same object. You modify one, you see the modification in all of them.

If you want different lists, you can do this way:

plot_data = [[] for _ in positions]

for example:

>>> pd = [[] for _ in range(3)]
>>> pd
[[], [], []]
>>> pd[0].append(1)
>>> pd
[[1], [], []]
joaquin
  • 82,968
  • 29
  • 138
  • 152
  • 1
    Does someone have a good explanation of the underscore black magic? I believe it's being used as a [throwaway variable](http://stackoverflow.com/questions/5893163/what-is-the-purpose-of-the-single-underscore-variable-in-python) but I still don't quite understand what that means. – Austin A Jul 28 '15 at 02:27
  • @AustinA what exactly you dont understand from the selected answer in the SO question you link ? – joaquin Jul 29 '15 at 08:06
  • 2
    @AustinA all that means is "I'm not interested in this". You don't assign the value to any variable so you can't reference it later on. - Normally, `for i in range(3)` would give you access to a dynamically changing `i` which first will be 0, then 1, then 2. But notice how the above code doesn't care about this value at all. It's unused. So you might as well `_` throw it away. – kram1032 Mar 26 '16 at 22:22
  • This is awesome. Totally going to change my style of programing in Python! Feel a bit silly for not finding this earlier. – ntk4 Jan 17 '17 at 06:36
3
import csv
cols = [' V1', ' I1'] # define your columns here, check the spaces!
data = [[] for col in cols] # this creates a list of **different** lists, not a list of pointers to the same list like you did in [[]]*len(positions) 
with open('data.csv', 'r') as f:
    for rec in csv.DictReader(f):
        for l, col in zip(data, cols):
            l.append(float(rec[col]))
print data

# [[3.0, 3.0], [0.01, 0.01]]
eumiro
  • 207,213
  • 34
  • 299
  • 261