当深层副本更改时,原始列表的元素会发生更改

2024-04-23 20:18:52 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个全局列表变量。我将全局列表的一个浅拷贝作为参数发送给另一个函数。在

令人惊讶的是,当我从被调用函数的参数中删除一些元素时,原始列表会发生更改。在

有人能告诉我为什么会发生这种事,以及如何防止这种情况发生?在

下面是简化的代码示例:

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)

Tags: 函数列表参数ifdef全局poproute
3条回答

我想你对这些条款感到困惑。在

浅拷贝是一种复制类型,其中被复制列表的元素仍然与原始列表的元素绑定到相同的内存值。在

你在找什么 Here is a good source to find out.

还有: Wikipedia

我想你需要一个关于浅拷贝和深拷贝的快速提醒,以及如何制作深拷贝。在

>>> a = [[1,2], [3,4]] # a list of mutable elements
>>> b = a[:]
>>> c = list(a)

bc都是{}的浅拷贝,可以检查ab和{}是否是不同的对象,因为它们不共享相同的id。在

^{pr2}$

但是,ab和{}的每个元素仍然是对我们在定义a时创建的列表[1,2]和{}的引用。当我们对列表中的一个项进行变异时,这一点就变得很清楚了:

>>> c[1][1] = 42
>>> a
[[1, 2], [3, 42]]
>>> b
[[1, 2], [3, 42]]
>>> c
[[1, 2], [3, 42]]

如您所见,第二个列表的第二个元素在ab和{}中发生了变化。 现在,要制作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和{}中的第二个列表是不同的对象:

>>> 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]]

python使用对对象的引用,这意味着allCandidatePaths和{}都指向内存中的同一个列表,您可以使用它们来更改列表。在

为了防止这种情况发生,在函数saveCandidateRoutes的开头添加以下指令candidateRoutes = list(candidateRoutes)list()函数将在内存中创建原始列表的另一个副本,并将其引用分配给candidateRoutes。在

因此,当您使用candidateRoutes时,您将不会处理main函数中的原始列表,而是处理另一个列表。在

相关问题 更多 >