python按值而不是按引用列出

python按值而不是按引用列出,python,list,reference,Python,List,Reference,让我们举个例子 a=['help', 'copyright', 'credits', 'license'] b=a b.append('XYZ') b ['help', 'copyright', 'credits', 'license', 'XYZ'] a ['help', 'copyright', 'credits', 'license', 'XYZ'] 我想在列表“b”中添加值,但列表“a”的值也已更改。 我想我不知道为什么会这样(python通过引用传递列表)。 我的问题是“如何通过

让我们举个例子

a=['help', 'copyright', 'credits', 'license']
b=a
b.append('XYZ')
b
['help', 'copyright', 'credits', 'license', 'XYZ']
a
['help', 'copyright', 'credits', 'license', 'XYZ']
我想在列表“b”中添加值,但列表“a”的值也已更改。
我想我不知道为什么会这样(python通过引用传递列表)。

我的问题是“如何通过值传递它,以便在“a”中添加“b”不会改变值?”

在Python中不能通过值传递任何内容。如果要复制
a
,可以明确执行,如中所述:


要创建列表的副本,请执行以下操作:

b = a[:]
此外,您还可以执行以下操作:

b = list(a)
这将适用于任何序列,即使是那些不支持索引器和切片的序列…

b=list(a)


请参阅。

执行
b=a
操作时,只需创建另一个指向a相同内存的指针, 这就是为什么当您附加到b时,a也会发生变化

您需要创建副本,操作如下:

b = a[:]

要复制列表,可以使用
list(a)
a[:]
。在这两种情况下,都会创建一个新对象。
但是,这两种方法在可变对象集合方面存在局限性,因为内部对象保持其引用完好无损:

>>> a = [[1,2],[3],[4]]

>>> b = a[:]
>>> c = list(a)

>>> c[0].append(9)

>>> a
[[1, 2, 9], [3], [4]]
>>> c
[[1, 2, 9], [3], [4]]
>>> b
[[1, 2, 9], [3], [4]]
>>> 
如果需要对象的完整副本,则需要


我发现我们可以使用extend()来实现copy()的函数


就性能而言,我最喜欢的答案是:

b.extend(a)
检查相关备选方案在性能方面的相互比较:

In [1]: import timeit

In [2]: timeit.timeit('b.extend(a)', setup='b=[];a=range(0,10)', number=100000000)
Out[2]: 9.623248100280762

In [3]: timeit.timeit('b = a[:]', setup='b=[];a=range(0,10)', number=100000000)
Out[3]: 10.84756088256836

In [4]: timeit.timeit('b = list(a)', setup='b=[];a=range(0,10)', number=100000000)
Out[4]: 21.46313500404358

In [5]: timeit.timeit('b = [elem for elem in a]', setup='b=[];a=range(0,10)', number=100000000)
Out[5]: 66.99795293807983

In [6]: timeit.timeit('for elem in a: b.append(elem)', setup='b=[];a=range(0,10)', number=100000000)
Out[6]: 67.9775960445404

In [7]: timeit.timeit('b = deepcopy(a)', setup='from copy import deepcopy; b=[];a=range(0,10)', number=100000000)
Out[7]: 1216.1108016967773

如果要复制一维列表,请使用

b = a[:]
但是,如果
a
是一个二维列表,那么这将不适用于您。也就是说,
a
中的任何更改也将反映在
b
中。在这种情况下,使用

b = [[a[x][y] for y in range(len(a[0]))] for x in range(len(a))]

正如菲哈格在回答中提到的

b = a[:]
将适用于您的情况,因为切片列表会创建列表的新内存id(这意味着您不再引用内存中的同一对象,并且对其中一个对象所做的更改不会反映在另一个对象中)

然而,有一个小问题。如果您的列表是多维的,如列表中的列表,那么简单的切片无法解决此问题。在较高维度(即原始列表中的列表)中所做的更改将在两个维度之间共享

别担心,有解决办法。模块拷贝有一种巧妙的拷贝技术来解决这个问题

from copy import deepcopy

b = deepcopy(a)

将复制具有新内存id的列表,无论它包含多少级别的列表

我推荐以下解决方案:

b = []
b[:] = a

这将把所有元素从a复制到b。副本将是价值副本,而不是参考副本。

感谢您将性能引入讨论,这帮助我决定使用哪种方法。我刚刚找到了您的答案,感谢您的高质量回复!在讨论Python时,通常不考虑性能,对于庞大的数据集来说,性能会有所不同。正如Jordan Pagni所提到的,如果您的列表是多维的,如列表中的列表(以及更多),那么唯一有效的解决方案就是耗时最长的解决方案:b=deepcopy(a)
extend()
调用的测试用例与其他调用不可比。要使用
extend()。因此,通过跳过列表对象的初始化,可以有效地为
extend()
提供优势。要更正测试,请将
b=[]
从设置移动到测试下的语句,如
b=[];b、 扩展(a)
。这将改变结果,有利于使用切片创建副本的第二种情况。为什么
b=list(a)
花费的时间是
b=a[:]
的两倍?常规副本和深度副本之间的区别是什么?为什么会发生上述情况?我想我有一个大致的理解,这似乎是op在第二层遇到的相同问题。它内部是如何工作的?回答得很好,乔丹!谢谢你知道原因吗?答案很好,特别是它提到了初始解决方案将失败的情况(嵌套对象、其他对象列表)和解决方案(deepcopy())。对我来说不起作用。我对
b
所做的任何更改也可以在
a
@Mannix中看到。你能在一个新问题中发布你有哪些问题(即断言应该失败)?最有可能的是,您不是在修改列表本身,而是在修改它的元素。如果您想要一个元素也是副本的新列表,请创建一个。但是,如果a是二维列表,这对二维数组不起作用,可以使用映射函数:old_array=[[2,3],[4,5].#python2.*new_array=map(list,old#array)#python3.*new_array=list(map(list,old#array))@Pythoner您描述的代码适用于二维列表,而不是数组<代码>复制。深度复制(某物)
对两者都有效。但是,如果你的列表是2D的,或者是任何数据结构,但只是一个简单的列表,那么你会遇到一个与这里不同的问题。这只是一个技术问题,但是python变量并不是真正的指针。更准确的说法是,当您执行
b=a
时,您创建了对
a
引用的列表对象的另一个引用。这并不比
b=a[:]更好
b = a[:]
from copy import deepcopy

b = deepcopy(a)
b = []
b[:] = a