In Python, you use [:]
when reassigning a variable to an original value (defined prior to the loop) at the start of each iteration. That is to say:
original_1D = ['o', 'o', 'o']
for i in range(0,3):
new = original_1D[:] # revert back to 'original_1D' list defined before loop
new[i] = 'X'
print new
produces output that is both desired and expected:
['X', 'o', 'o']
['o', 'X', 'o']
['o', 'o', 'X']
My issue arises if the original list is multi-dimensional (original_2D
). For example:
original_2D = [['o', 'o', 'o'],['o', 'o', 'o']]
for i in range(0,3):
new = original_2D[:] # revert back to 'original_2D' list defined before loop
new[0][i] = 'X'
print new
From this, I want the following output:
# Desired
[['X', 'o', 'o'], ['o', 'o', 'o']]
[['o', 'X', 'o'], ['o', 'o', 'o']]
[['o', 'o', 'X'], ['o', 'o', 'o']]
but no! I get this:
# Actual
[['X', 'o', 'o'], ['o', 'o', 'o']]
[['X', 'X', 'o'], ['o', 'o', 'o']]
[['X', 'X', 'X'], ['o', 'o', 'o']]
as if the original_2D
list gets overwritten which each iteration.
What am I doing wrong?
In Python, you use [:]
when reassigning a variable to an original value
No, you use it to create a full-length slice (i.e. shallow copy) of a sequence. If the original value is an immutable sequence (e.g. strings and tuples) it's unnecessary, and if the original value isn't a sequence it won't work.
Note that I have emphasised shallow copy above - the new object created by the slice contains references to the same objects as the original. If your original sequence contains references to mutable objects (like, for example, lists), this can be a problem.
Either use copy.deepcopy
to create a deep (rather than shallow) copy:
from copy import deepcopy
new = deepcopy(original2D)
or explicitly create shallow copies of the sub-lists too, using e.g. a list comprehension:
new = [row[:] for row in original2D]
The former scales more easily to higher dimensions.
In python lists are always passed by object reference. So if you copy a list of lists like you did, you will still have the same list references in your list. You have to make a deep copy to solve your problem. Import the following package and change the line new = original_2D[:]
to:
from copy import deepcopy
original_2D = [['o', 'o', 'o'],['o', 'o', 'o']]
for i in range(0,3):
new = deepcopy(original_2D) # Change this line.
new[0][i] = 'X'
print new
import copy
original_2D = [['o', 'o', 'o'],['o', 'o', 'o']]
for i in range(0,3):
new = copy.deepcopy(original_2D[:])
new[0][i] = 'X'
print new