我有一个全局列表(列表)变量。我将全局列表的浅表副本作为参数发送给另一个函数。
令人惊讶的是,当我从调用函数中的参数中删除一些元素时,原始列表会发生变化。
有人可以告诉我它为什么会发生以及如何防止这种情况发生吗?
以下是简化的代码示例:
def saveCandidateRoutes(candidateRoutes):
for route in candidateRoutes:
if route: # check if the list, 'route', is empty.
tweetId = route.pop(0)
stanox = route.pop(-1)
....
def main():
global allCandidatePaths
copyOfAllCandidatePaths= list(allCandidatePaths) # making a deep copy
result = saveCandidateRoutes(copyOfAllCandidatePaths)
答案 0 :(得分:2)
python使用对象的引用,这意味着allCandidatePaths
和candidateRoutes
都指向内存中的相同列表,您可以使用它们来更改列表。
为了防止这种情况发生,请在函数saveCandidateRoutes
的开头添加此指令candidateRoutes = list(candidateRoutes)
。 list()
函数将在内存中创建原始列表的另一个副本,并将其引用分配给candidateRoutes
。
因此,当您使用candidateRoutes
时,您将不会处理主函数中的原始列表,但您将处理另一个列表。
答案 1 :(得分:1)
我认为你对这些条款感到困惑。
浅拷贝是复制的类型,其中复制列表的元素仍然与相同的内存值绑定原始列表的元素强>
您正在寻找的是深度复印 Here is a good source to find out.
还有: Wikipedia
答案 2 :(得分:1)
我认为您需要快速提醒浅层和深层副本,以及如何制作深层副本。
>>> a = [[1,2], [3,4]] # a list of mutable elements
>>> b = a[:]
>>> c = list(a)
b
和c
都是a
的浅层副本,您可以检查a
,b
和c
是不同的对象,因为他们不共享id
。
>>> id(a)
140714873892592
>>> id(b)
140714810215672
>>> id(c)
140714873954744
但是,a
,b
和c
的每个元素仍然是我们在定义时创建的列表[1,2]
和[3,4]
的引用。当我们改变列表中的项目时,这一点就变得清晰了:
>>> c[1][1] = 42
>>> a
[[1, 2], [3, 42]]
>>> b
[[1, 2], [3, 42]]
>>> c
[[1, 2], [3, 42]]
如您所见,第二个列表的第二个元素在a
,b
和c
中发生了变化。
现在,要制作a
的深层副本,您有几种选择。一个是列表理解,您可以复制每个子列表:
>>> d = [sublist[:] for sublist in a]
>>> d
[[1, 2], [3, 42]]
>>> d[1][1] = 23
>>> d
[[1, 2], [3, 23]]
>>> a
[[1, 2], [3, 42]]
如您所见,a
中的42未更改为23
,因为a
和d
中的第二个列表是不同的对象:
>>> id(a[1])
140714873800968
>>> id(d[1])
140714810230904
创建深层副本的另一种方法是使用copy.deepcopy
:
>>> from copy import deepcopy
>>> e = deepcopy(a)
>>> e
[[1, 2], [3, 42]]
>>> e[1][1] = 777
>>> e
[[1, 2], [3, 777]]
>>> a
[[1, 2], [3, 42]]
答案 3 :(得分:0)
浅拷贝复制对象但不复制任何属性。对于列表,这意味着它的元素被分配给新列表的元素。如果元素是整数,则会得到一个全新的列表,因为int是基本类型*,因此不需要复制它。如果元素是列表,就像在二维列表中那样,它们会被分配给副本,因此每个元素都有两个引用,每个元素一个。如果要复制内部列表的元素,则需要深层复制,以递归方式复制每个对象的属性(在本例中为元素)。
*原始类型与非原始类型之间实际上没有区别,但这相当于它在本解释范围内的工作方式。