When I define a list and try to change a single item like this:
list_of_lists = [['a', 'a', 'a'], ['a', 'a', 'a'], ['a', 'a', 'a']]
list_of_lists[1][1] = 'b'
for row in list_of_lists:
print row
It works as intended. But when I try to use list comprehension to create the list:
row = ['a' for range in xrange(3)]
list_of_lists = [row for range in xrange(3)]
list_of_lists[1][1] = 'b'
for row in list_of_lists:
print row
It results in an entire column of items in the list being changed. Why is this? How can I achieve the desired effect with list comprehension?
Think about if you do this:
This happens because
rowandrow2are two different names for the same list (you haverow is row2) – your example with nested lists only obscures this a little.To make them different lists, you can cause it to re-run the list-creation code each time instead of doing a variable assignment:
or, create a new list each time by using a slice of the full old list:
Although this isn’t guaranteed to work in general for all sequences – it just happens that list slicing makes a new list for the slice. This doesn’t happen for, eg, numpy arrays – a slice in those is a view of part of the array rather than a copy. If you need to work more generally than just lists, use the
copymodule:Also, note that
rangeisn’t the best name for a variable, since it shadows the builtin – for a throwaway like this,_is reasonably common.