按值而不是按引用对Python列表进行操作

205 投票
11 回答
290244 浏览
提问于 2025-04-17 09:36

我们来看一个例子

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 个回答

44

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

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
165

要复制一个列表,你可以使用 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]]
>>> 
286

在Python中,你不能通过值来传递任何东西。如果你想要复制一个叫a的东西,你可以明确地这样做,具体方法可以参考官方的Python常见问题解答

b = a[:]

撰写回答