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通过引用列表)。
我的问题是“如何通过价值来传递它,使得追加'b'不会改变'a'中的值?

正如在Python官方FAQ中回答的那样:

 b = a[:] 

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

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

如果你想要一个你的对象的完整副本,你需要copy.deepcopy

 >>> from copy import deepcopy >>> a = [[1,2],[3],[4]] >>> b = a[:] >>> c = deepcopy(a) >>> c[0].append(9) >>> a [[1, 2], [3], [4]] >>> b [[1, 2], [3], [4]] >>> c [[1, 2, 9], [3], [4]] >>> 

在性能方面,我最喜欢的答案是:

 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 = list(a) 

这将适用于任何序列,即使那些不支持索引器和片…

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

 b = a[:] 

当你做b = a你只需要创build另外一个指向a的同一个内存的指针,这就是为什么当你追加到b时也会有一些变化。

你需要创build一个和这样做的副本

 b = a[:] 

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

 b = a[:] 

但是,如果a是二维列表,这不适用于你。 也就是说,a中的任何变化都会反映在b中。 在这种情况下,使用

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

正如phihag在他的回答中提到的那样,

 b = a[:] 

将适用于你的情况,因为切片列表会创build列表的新内存ID(这意味着您不再引用内存中的同一个对象,并且对其中一个进行的更改不会反映在其他内存中)。

但是,有一个小问题。 如果你的列表是多维的,就像列表中的列表一样,简单的切片就不能解决这个问题。 更高维度的更改,即原始列表内的列表将在两者之间共享。

不要担心,有一个解决scheme。 模块副本有一个漂亮的复制技术,照顾这个问题。

 from copy import deepcopy b = deepcopy(a) 

将复制一个新的内存ID列表,无论它包含多less级别的列表!

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

 a=['help', 'copyright', 'credits', 'license'] b = [] b.extend(a) b.append("XYZ")