Cloned list seems to be functioning as an alias, even though explicitly declared as a a clone
I am having some trouble with th开发者_运维知识库e following script. It should make 3 copies of the following list so that they can be modified independently. However, it seems to be creating 3 clones of the same list, and when you modify one you modify them all. Here is the function:
def calculateProportions(strategies,proportions):
import itertools
combinations = []
columns = list(itertools.product(strategies,repeat=3))
for i in range(0,len(columns)):
columns[i] = list(columns[i])
for n in range(0,len(strategies)):
combinations.append(columns[:])
combinations[0][0][0] = "THIS SHOULD ONLY BE IN ONE PLACE"
print combinations
strategies = [[0,0],[0,50],[50,50]]
calculateProportions(strategies,[])
Notice how, when you run this, you see the string "THIS SHOULD BE IN ONE PLACE" 3 times (position [0][0][0],[1][0][0], and [2][0][0], not once. This appears to be because the lists are aliased together rather than cloned. However I explicitly cloned it.
I have spent the last hour banging my head into the table on this. Your suggested solutions are much appreciated!
You're only performing a shallow copy when you clone columns
, i.e. the list is cloned but its items are not, so the same item references are used in both combinations
and columns
.
You can use the copy.deepcopy() function to perform a deep copy of the object:
def calculateProportions(strategies,proportions):
import copy
import itertools
combinations = []
columns = list(itertools.product(strategies, repeat=3))
for i in range(0, len(columns)):
columns[i] = list(columns[i])
for n in range(0, len(strategies)):
combinations.append(copy.deepcopy(columns))
Or, more simply, a list comprehension:
def calculateProportions(strategies,proportions):
import itertools
combinations = []
columns = list(itertools.product(strategies, repeat=3))
for i in range(0, len(columns)):
columns[i] = list(columns[i])
for n in range(0, len(strategies)):
combinations.append([item[:] for item in columns])
Getting a copy of a list like list[:]
does not create copies of the elements contained in the list (i.e. it is a flat copy, not a deep copy). The following example code illustrates this:
>>> n1 = [1, 2]
>>> n2 = [3, 4]
>>> l1 = [n1, n2]
>>> l2 = l1[:]
>>> l2[0] = "was n1" # change in l1 only
>>> l1
[[1, 2], [3, 4]]
>>> l2
['was n1', [3, 4]]
>>> l2[1][0] = "was 3 in n2" # affects both l1 and l2
>>> l1
[[1, 2], ['was 3 in n2', 4]]
>>> l2
['was n1', ['was 3 in n2', 4]]
As suggested by ulidtko, the copy module might help in your case.
when you write
l = alist[:]
you're doing a shallow copy. that is to say that the list is different, but the two lists are pointing to the same objects. so if you modify one element of a list, the element in the other list will be modified too.
you need to make a deep copy, ie. copying the list and all the object in the list.
import copy
copy.deepcopy()
>>> import copy
>>> help(copy)
In the very first lines, you can see functions copy
and deepcopy
. These correspond to shallow and deep copying. For details, refer to http://en.wikipedia.org/wiki/Object_copy
Instead of trying to fix up the deep copies, I would just create the desired data with nested list comprehensions. This also avoids the ugly manual "accumulation" of the final data.
def calculateProportions(strategies, proportions):
import itertools
combinations = [
[list(x) for x in itertools.product(strategies, repeat = 3)]
for strategy in strategies
]
combinations[0][0][0] = "THIS SHOULD ONLY BE IN ONE PLACE"
print combinations
精彩评论