Lista de Python por valor, no por referencia

Tomemos un ejemplo

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

Quería agregar un valor en la lista ‘b’, pero el valor de la lista ‘a’ también ha cambiado.
Creo que tengo poca idea de por qué es así (python pasa las listas por referencia).
Mi pregunta es “¿cómo puedo pasarlo por valor para que la adición de ‘b’ no cambie los valores en ‘a’?

Como se responde en las preguntas frecuentes oficiales de Python :

 b = a[:] 

Para copiar una lista puede usar la list(a) o a[:] . En ambos casos se crea un nuevo objeto.
Sin embargo, estos dos métodos tienen limitaciones con las colecciones de objetos mutables, ya que los objetos internos mantienen sus referencias intactas:

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

Si desea una copia completa de sus objetos necesita 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]] >>> 

En términos de rendimiento mi respuesta favorita sería:

 b.extend(a) 

Compruebe cómo las alternativas relacionadas se comparan entre sí en términos de rendimiento:

 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 

Además, puedes hacer:

 b = list(a) 

Esto funcionará para cualquier secuencia, incluso aquellas que no admiten indizadores y segmentos …

Si desea copiar una lista unidimensional, utilice

 b = a[:] 

Sin embargo, si a es una lista bidimensional, esto no funcionará para usted. Es decir, cualquier cambio en a también se reflejará en b . En ese caso, utilice

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

Como lo menciona phihag en su respuesta,

 b = a[:] 

funcionará para su caso, ya que cortar una lista crea una nueva identificación de memoria de la lista (lo que significa que ya no hace referencia al mismo objeto en su memoria y los cambios que realice en uno no se reflejarán en el otro).

Sin embargo, hay un pequeño problema. Si su lista es multidimensional, como en las listas dentro de listas, simplemente cortar no resolverá este problema. Los cambios realizados en las dimensiones superiores, es decir, las listas dentro de la lista original, se compartirán entre los dos.

No te preocupes, hay una solución. La copia del módulo tiene una técnica de copia ingeniosa que se encarga de este problema.

 from copy import deepcopy b = deepcopy(a) 

¡copiará una lista con una nueva identificación de memoria sin importar cuántos niveles de listas contenga!

Para crear una copia de una lista haz esto:

 b = a[:] 

Cuando haces b = a , simplemente creas otro puntero a la misma memoria de a , es por eso que cuando agregas a b , a cambia también.

Necesitas crear una copia de y se hace así:

 b = a[:] 

Encontré que podemos usar extend () para implementar la función de copiar ()

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

Recomendaría la siguiente solución:

 b = [] b[:] = a 

Esto copiará todos los elementos de a a b. La copia será copia de valor, no copia de referencia.