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

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

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

Как ответили в официальном FAQ Python :

 b = a[:] 

Чтобы скопировать список, вы можете использовать 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]] >>> 

Кроме того, вы можете:

 b = list(a) 

Это будет работать для любой последовательности, даже тех, которые не поддерживают индексаторы и срезы …

Что касается производительности, моим любимым ответом было бы:

 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 

Чтобы создать копию списка, выполните следующие действия:

 b = a[:] 

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

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

 b = a[:] 

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

 b = a[:] 

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

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

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

 b = a[:] 

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

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

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

 from copy import deepcopy b = deepcopy(a) 

скопирует список с новым идентификатором памяти независимо от того, сколько уровней он содержит!

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

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