Reassign variable to original value (defined prior

2019-09-15 10:53发布

问题:

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?

回答1:

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.



回答2:

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


回答3:

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