Estoy trabajando a través de Udacity y Dave Evans presentó un ejercicio sobre las propiedades de la lista
list1 = [1,2,3,4] list2 = [1,2,3,4] list1=list1+[6] print(list1) list2.append(6) print(list2) list1 = [1,2,3,4] list2 = [1,2,3,4] def proc(mylist): mylist = mylist + [6] def proc2(mylist): mylist.append(6) # Can you explain the results given by the four print statements below? Remove # the hashes # and run the code to check. print (list1) proc(list1) print (list1) print (list2) proc2(list2) print (list2)
La salida es
[1, 2, 3, 4, 6] [1, 2, 3, 4, 6] [1, 2, 3, 4] [1, 2, 3, 4] [1, 2, 3, 4] [1, 2, 3, 4, 6]
Entonces, en una función, la adición de un 6 al conjunto no se muestra, pero sí cuando no está en una función.
Entonces, en una función, la adición de un 6 al conjunto no se muestra, pero sí cuando no está en una función.
No, eso no es lo que pasa.
Lo que sucede es que cuando ejecutas mylist = mylist + [6]
, estás creando efectivamente una lista completamente nueva y colocándola en la variable mylist
local. Esta variable mylist
desaparecerá después de la ejecución de la función y la lista recién creada también desaparecerá.
OTOH cuando ejecuta mylist.append(6)
no crea una nueva lista. Ya obtienes la lista en la variable mylist
y agregas un nuevo elemento a esta misma lista. El resultado es que la lista (que también es señalada por list2
) se modificará. La variable mylist
desaparecerá de nuevo, pero en este caso modificó la lista original.
Veamos si una explicación más visual te puede ayudar 🙂
proc()
Cuando escribe list1 = [1, 2, 3, 4, 5]
está creando un nuevo objeto de lista (en el lado derecho del signo igual) y creando una nueva variable, list1
, que apuntará a este objeto.
Luego, cuando llama a proc()
, crea otra nueva variable, mylist
, y dado que pasa list1
como parámetro, mylist
apuntará al mismo objeto:
Sin embargo, la operación mylist + [6]
crea un objeto de lista completamente nuevo cuyo contenido es el contenido del objeto señalado por mylist
más el contenido del siguiente objeto de lista, es decir, [6]
. Dado que atribuye este nuevo objeto a mylist
, nuestro escenario cambia un poco y mylist
ya no apunta al mismo objeto señalado por list1
:
Lo que no he dicho es que mylist
es una variable local : desaparecerá después del final de la función proc()
. Entonces, cuando la ejecución de proc()
terminó, el mylist
se fue:
Como ninguna otra variable apunta al objeto generado por mylist + [6]
, también desaparecerá (ya que el recolector de basura * lo recogerá):
Tenga en cuenta que, al final, el objeto apuntado por list1
no se cambia.
proc2()
Todo cambia cuando llamas proc2()
. Al principio, es lo mismo: creas una lista …
… y páselo como parámetro a una función, que generará una variable local:
Sin embargo, en lugar de utilizar el operador de concatenación +
, que genera una nueva lista, aplica el método append()
a la lista existente. El método append()
no crea un nuevo objeto ; en cambio, cambia la existente:
Una vez finalizada la función, la variable local desaparecerá, pero el objeto original señalado por ella y por list1
ya se modificará:
Como todavía está señalado por list1
, la lista original no se destruye.
EDITAR : si quieres echar un vistazo a todo esto que sucede antes de que tus ojos solo vayan a este simulador radicalmente asombroso :
* Si no sabes qué es el recolector de basura … bueno, lo descubrirás poco después de comprender tu propia pregunta.
Las variables en python siempre se pueden considerar como referencias. Cuando llama a una función con un argumento, está pasando una referencia a los datos reales.
Cuando utiliza el operador de asignación ( =
), está asignando ese nombre para referirse a un objeto completamente nuevo. Entonces, mylist = mylist + [6]
crea una nueva lista que contiene los contenidos antiguos de mylist, así como 6, y asigna la variable mylist para referirse a la nueva lista. list1 sigue apuntando a la lista anterior, así que nada cambia.
Por otro lado, cuando usa .append, eso es en realidad agregar un elemento a la lista a la que se refiere la variable, no está asignando nada nuevo a la variable. Así que tu segunda función modifica la lista a la que se refiere list2.
Normalmente, en el primer caso en la función proc
, solo podría cambiar la lista global por asignación si declara
global mylist
Primero y no pasó mylist
como parámetro. Sin embargo, en este caso obtendría un mensaje de error que mylist
que mylist
es global y local: el name 'mylist' is local and global
. Lo que sucede en el proc
es que se crea una lista local cuando tiene lugar la asignación. Como las variables locales desaparecen cuando finaliza la función, el efecto de cualquier cambio en la lista local no se propaga al rest del progtwig cuando se imprime posteriormente.
Pero en la segunda función proc2
está modificando la lista agregándola en lugar de asignársela, por lo que la palabra clave global
no es necesaria y los cambios en la lista se muestran en otra parte.
Esto, de una forma u otra, es una pregunta muy común. Me dio un golpe al explicar el parámetro de Python que pasé hace un par de días . Básicamente, uno de estos crea una nueva lista y el otro modifica el existente. En este último caso, todas las variables que hacen referencia a la lista “ven” el cambio porque sigue siendo el mismo objeto.
En la tercera línea, hiciste esto.
list1=list1+[6]
Entonces, cuando hiciste lo siguiente después de la línea anterior,
print (list1)
que imprimió la lista1 que creó al inicio y el procedimiento proc, que agrega list1 + [6] que crea una nueva lista dentro de la función proc. Donde, cuando está agregando [6], no está creando una lista nueva sino que está agregando un elemento de lista a una lista ya existente.
Pero, tenga en cuenta. En la línea 7, volviste a crear la lista.
list1 = [1,2,3,4]
Ahora quería imprimir la lista1 llamándola explícitamente, lo que imprimirá la lista1 que reinicializó de nuevo pero no la anterior.
Además de las respuestas completas que ya se dieron, también vale la pena tener en cuenta que, si desea la misma syntax de aspecto:
mylist = mylist + [6]
… pero aún desea que la lista se actualice “en el lugar”, puede hacer:
mylist += [6]
Lo que, aunque parece que haría lo mismo que la primera versión, es en realidad lo mismo que:
mylist.extend([6])
(Tenga en cuenta que extend
toma el contenido de un iterable y los agrega uno por uno, mientras que el append
toma lo que se le da y lo agrega como un solo elemento. Vea el apéndice frente a la extensión para obtener una explicación completa).