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?
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:or explicitly create shallow copies of the sub-lists too, using e.g. a list comprehension:
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: