2010-09-03 13 views
7

Cuando ejecuto (estoy usando el shell interactivo) estas declaraciones me sale esto:¿Cuál es la diferencia entre LIST.append (1) y la LISTA DE LISTA = + [1] (Python)

L=[1,2,3] 
K=L 

L.append(4) 

L 
[1,2,3,4] 
K 
[1,2,3,4] 

pero cuando lo haga exactamente lo mismo que la sustitución de L.append (4) con L = L + [4] me sale:

L 
[1,2,3,4] 
K 
[1,2,3] 

Es esto algún tipo de cosas referencia? ¿Por qué pasó esto?

Otra cosa graciosa que noté es que L + = [4] actúa como .append, lo cual es extraño ya que pensé que actuaría como L = L + [4].

La aclaración de todo esto sería muy apreciada.

Gracias

+0

'' + = es raro en Python. por ejemplo 'a = (1, 2); a + = (2,) 'produce' (1, 2, 3) '! Esto es exactamente lo contrario de la situación de lista donde ite modifica la lista en su lugar. No hay forma de modificar una tupla en su lugar.esta es la razón por la cual mucha gente prefiere usar siempre la forma 'a = a + b'. – aaronasterling

+0

no, no, después de a = (1, 2); a + = (2), a es (1,2,2) ¿qué tiene de raro eso? – Kugel

+0

Creo que quiso decir 'a + = (3,)'. Y es extraño que te permita modificar una tupla (inmutable) en su lugar de esta manera. – efritz

Respuesta

2

Con append que se está modificando la lista directamente. Con L=L+[4], está haciendo una copia del original L y agrega un nuevo elemento, luego asignando ese resultado a L y rompiendo su equivalencia a K.

No estoy seguro del comportamiento de +=.

+0

'+ =' parece comportarse como 'append' (Acabo de probarlo) –

+1

@Andre, no. Se comporta como 'extender'. – habnabit

+0

tienes razón '+ = 5' no funcionó .. –

15
L.append(4) 

Esto agrega un elemento al final de la lista existente L.

L += [4] 

El operador += invoca el método mágico __iadd__(). Resulta que list anula el método __iadd__() y lo hace equivalente a extend() que, como append(), agrega elementos directamente a una lista existente.

L = L + [4] 

L + [4] genera una nueva lista que es igual a L con 4 agregado al final. Esta nueva lista se asigna de nuevo a L. Como ha creado un nuevo objeto de lista, esta tarea no modifica el K.

Podemos utilizar id() para identificar cuando se crea una nueva referencia de objeto:

>>> L = [1, 2, 3] 
>>> id(L) 
152678284 
>>> L.append(4) 
>>> id(L) 
152678284 

>>> L = [1, 2, 3] 
>>> id(L) 
152680524 
>>> L = L + [4] 
>>> id(L) 
152678316 
+0

@ Aaron Sí, tienes razón. Fijo. –

0

En el primer ejemplo K y L nombres de las variables se refieren al mismo objeto, por lo que cuando se invoca un método de mutación de ese objeto, los cambios se ven obviamente a través de ambas referencias. En el segundo ejemplo + operador invoca list.__add__ que devuelve nuevo objeto (concatenación de dos listas) y L nombre ahora se refiere a este nuevo objeto, mientras que K está intacto.

+0

Entonces, cuando asigno una variable a una lista, ¿obtiene la referencia al objeto? ¿Esto es porque la lista en realidad no es la lista, sino más bien una referencia también? Creo que lo entiendo ahora. Esto podría suceder con una lista y diccionario ¿no? Porque en realidad son ambas referencias al objeto en sí. Muchas gracias por la aclaración. Las cosas que leí en otro lado eran solo palabras vacías y realmente no dije que al usar el operador + invocado a la lista .__ add__ Gracias (^_^) – aitee

+0

¿Alguna idea sobre el + =? – aitee

+0

No solo 'list' y' dict', * everything * en Python es un objeto. Todos los objetos se almacenan en el montón y todas las variables son solo referencias. Pero algunos objetos son inmutables (como 'int's y' string's), y algunos objetos inmutables son internados, por lo que no obtienes este comportamiento desconcertante. Debe distinguir entre modificar los datos y modificar la asignación entre nombres de variables y datos. Lo último es lo que sucede cuando asigna algo a una variable. Tenga en cuenta, sin embargo, que la asignación de variables en sí misma puede ser parte de los datos si representa miembros de un objeto. – rkhayrov

1

Si eres curioso acerca de los códigos de bytes:

>>> def L_app(): 
...  L.append(4) 
... 
>>> def L_add(): 
...  L = L + [ 4 ] 
... 
>>> def L_add_inplace(): 
...  L += [ 4 ] 
... 
>>> dis.dis(L_app) 
    2   0 LOAD_GLOBAL    0 (L) 
       3 LOAD_ATTR    1 (append) 
       6 LOAD_CONST    1 (4) 
       9 CALL_FUNCTION   1 
      12 POP_TOP 
      13 LOAD_CONST    0 (None) 
      16 RETURN_VALUE 
>>> dis.dis(L_add) 
    2   0 LOAD_FAST    0 (L) 
       3 LOAD_CONST    1 (4) 
       6 BUILD_LIST    1 
       9 BINARY_ADD 
      10 STORE_FAST    0 (L) 
      13 LOAD_CONST    0 (None) 
      16 RETURN_VALUE 
>>> dis.dis(L_add_inplace) 
    2   0 LOAD_FAST    0 (L) 
       3 LOAD_CONST    1 (4) 
       6 BUILD_LIST    1 
       9 INPLACE_ADD 
      10 STORE_FAST    0 (L) 
      13 LOAD_CONST    0 (None) 
      16 RETURN_VALUE 
+0

el caso más interesante es el formulario '+ ='. – aaronasterling

+0

Aunque no soy nuevo en la programación, soy bastante nuevo en python. Esto (los códigos de bytes) no tiene mucho sentido para mí. ¿No son los bytecodes en general códigos que tienen un nivel más bajo que el idioma, que están más cerca del código de máquina y son más rápidos de ejecutar? Tal vez tengo la definición incorrecta. – aitee

+0

@aaronasterling: ¡muy interesante! Adicional. @aitee: sí, lo son. 'dis' imprime una 'buena' representación de los códigos de byte a los que se compila una función de Python. Esto a menudo es útil para ver qué está sucediendo "debajo del capó". – katrielalex

Cuestiones relacionadas