Список питонов по значению не по ссылке

Возьмем пример

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 "?"

Ответ 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[:]

Ответ 6

Когда вы делаете b = a, вы просто создаете другой указатель на ту же память a, поэтому при добавлении в b изменений a.

Вам нужно создать копию a и сделать это следующим образом:

b = a[:]

Ответ 7

Если вы хотите скопировать одномерный список, используйте

b = a[:]

Однако, если a является двумерным списком, это не сработает для вас. То есть любые изменения в также будут отражены в b. В этом случае используйте

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

Ответ 8

Как упоминалось в его ответе фигаг,

b = a[:]

будет работать для вашего случая, так как нарезка списка создает новый идентификатор памяти в списке (это означает, что вы больше не ссылаетесь на один и тот же объект в своей памяти, а изменения, которые вы делаете на один, не будут отображаться в другом).

Однако есть небольшая проблема. Если ваш список является многомерным, как в списках в списках, просто нарезка не решит эту проблему. Изменения, внесенные в более высокие размеры, т.е. Списки в исходном списке, будут разделены между ними.

Не волнуйся, есть решение. У копии модуля есть отличный способ копирования, который заботится об этой проблеме.

from copy import deepcopy

b = deepcopy(a)

скопирует список с новым идентификатором памяти независимо от количества уровней содержащихся в нем списков!

Ответ 9

Я обнаружил, что мы можем использовать функцию extend() для реализации функции copy()

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

Ответ 11

Я бы порекомендовал следующее решение:

b = []
b[:] = a

Это скопирует все элементы из a в b. Копия будет копией значения, а не копией ссылки.