python 按值列出而不是按引用列出[重复]
- 2024-12-17 08:30:00
- admin 原创
- 116
问题描述:
让我们举个例子
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”中的值?”
解决方案 1:
在 Python 中,您无法按值传递任何东西。如果您想复制,您可以明确地这样做,如官方 Python FAQa
中所述:
b = a[:]
解决方案 2:
要复制列表,您可以使用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]]
>>>
解决方案 3:
就性能而言,我最喜欢的答案是:
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
解决方案 4:
此外,您还可以执行以下操作:
b = list(a)
这对于任何序列都有效,即使那些不支持索引器和切片的序列......
解决方案 5:
如果要复制一维列表,请使用
b = a[:]
但是,如果a
是二维列表,则这不适合您。也就是说,中的任何更改a
也将反映在中b
。在这种情况下,使用
b = [[a[x][y] for y in range(len(a[0]))] for x in range(len(a))]
解决方案 6:
正如 phihag 在他的回答中提到的,
b = a[:]
适用于您的情况,因为切片列表会创建列表的新内存 ID(这意味着您不再引用内存中的同一个对象,并且对一个对象所做的更改不会反映在另一个对象中。)
但是,还有一个小问题。如果您的列表是多维的,例如列表中的列表,那么简单的切片无法解决这个问题。在更高维度(即原始列表中的列表)中所做的更改将在两者之间共享。
别担心,有解决办法。模块复制有一个巧妙的复制技术,可以解决这个问题。
from copy import deepcopy
b = deepcopy(a)
将会复制一个具有新内存 ID 的列表,无论它包含多少级列表!
解决方案 7:
当您这样做时,您只需创建指向ab = a
的同一内存的另一个指针,这就是为什么当您附加到b时,a也会发生变化。
您需要创建a的副本,方法如下:
b = a[:]
解决方案 8:
要创建列表的副本,请执行以下操作:
b = a[:]
解决方案 9:
我发现我们可以使用extend()来实现copy()的功能
a=['help', 'copyright', 'credits', 'license']
b = []
b.extend(a)
b.append("XYZ")
解决方案 10:
我推荐以下解决方案:
b = []
b[:] = a
这会将所有元素从 a 复制到 b。复制将是值复制,而不是引用复制。
解决方案 11:
b = list(a)