python列表的值不是通过引用

时间:2012-01-05 14:28:52

标签: 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通过引用传递列表)。
我的问题是“如何通过值传递它,以便附加'b'不会改变'a'中的值?”

11 个答案:

答案 0 :(得分:172)

正如official Python FAQ

所述
b = a[:]

答案 1 :(得分:121)

要复制列表,您可以使用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]]
>>> 

如果您需要对象的完整副本,则需要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]]
>>> 

答案 2 :(得分:25)

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

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

答案 3 :(得分:16)

另外,你可以这样做:

b = list(a)

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

答案 4 :(得分:8)

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

b = a[:]

但是,如果a是一个二维列表,那么这对你不起作用。也就是说,a中的任何更改也会反映在b中。在这种情况下,请使用

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

答案 5 :(得分:6)

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

b = a[:]

将适用于您的情况,因为切片列表会创建列表的新内存ID(意味着您不再引用内存中的同一对象,而您对其中的更改将不会反映在另一个中。)< / p>

然而,有一个小问题。如果您的列表是多维的,就像列表中的列表一样,只需切片就不能解决这个问题。更高维度所做的更改,即原始列表中的列表,将在两者之间共享。

不要烦恼,有一个解决方案。模块副本有一个漂亮的复制技术来处理这个问题。

from copy import deepcopy

b = deepcopy(a)
无论它包含多少级别的列表,

都会复制一个带有新内存ID的列表!

答案 6 :(得分:5)

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

b = a[:]

答案 7 :(得分:5)

执行b = a时,只需创建另一个指向 a 内存的指针, 这就是为什么当你追加 b a 也会改变。

您需要创建 a 复制,并且这样做:

b = a[:]

答案 8 :(得分:2)

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

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

答案 9 :(得分:2)

我会推荐以下解决方案:

b = []
b[:] = a

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

答案 10 :(得分:1)