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 '中的值?”

269560 次浏览

You cannot pass anything by value in Python. If you want to make a copy of a, you can do so explicitly, as described in the official Python FAQ:

b = a[:]

To create a copy of a list do this:

b = a[:]

Also, you can do:

b = list(a)

This will work for any sequence, even those that don't support indexers and slices...

When you do b = a you simply create another pointer to the same memory of a, that's why when you append to b , a changes too.

You need to create copy of a and that's done like this:

b = a[:]

To copy a list you can use list(a) or a[:]. In both cases a new object is created.
These two methods, however, have limitations with collections of mutable objects as inner objects keep their references intact:

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

If you want a full copy of your objects you need 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]]
>>>

I found that we can use extend() to implement the function of copy()

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

In terms of performance my favorite answer would be:

b.extend(a)

Check how the related alternatives compare with each other in terms of performance:

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

If you want to copy a one-dimensional list, use

b = a[:]

However, if a is a 2-dimensional list, this is not going to work for you. That is, any changes in a will also be reflected in b. In that case, use

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

As mentioned by phihag in his answer,

b = a[:]

will work for your case since slicing a list creates a new memory id of the list (meaning you are no longer referencing the same object in your memory and the changes you make to one will not be reflected in the other.)

However, there is a slight problem. If your list is multidimensional, as in lists within lists, simply slicing will not solve this problem. Changes made in the higher dimensions, i.e. the lists within the original list, will be shared between the two.

Do not fret, there is a solution. The module copy has a nifty copying technique that takes care of this issue.

from copy import deepcopy


b = deepcopy(a)

will copy a list with a new memory id no matter how many levels of lists it contains!

I would recommend the following solution:

b = []
b[:] = a

This will copy all the elements from a to b. The copy will be value copy, not reference copy.