¿Cuál es la diferencia entre la asignación de división que divide la lista completa y la asignación directa?

Veo en muchos lugares el uso de la asignación de sectores para las list . Soy capaz de entender su uso cuando se usa con índices (no predeterminados), pero no puedo entender su uso como:

 a_list[:] = ['foo', 'bar'] 

¿Cómo es eso diferente de

 a_list = ['foo', 'bar'] 

?

 a_list = ['foo', 'bar'] 

Crea una nueva list en la memoria y le señala el nombre a_list . Es irrelevante lo que una lista a_list antes.

 a_list[:] = ['foo', 'bar'] 

Llama al método a_list objeto a_list con una a_list como índice y una nueva list creada en la memoria como valor.

__setitem__ evalúa la slice para determinar qué índices representa y llama iter sobre el valor que se pasó. Luego, itera sobre el objeto, estableciendo cada índice dentro del rango especificado por la slice al siguiente valor del objeto. Para las list s, si el rango especificado por la slice no tiene la misma longitud que el iterable, la list se redimensiona. Esto le permite hacer una serie de cosas interesantes, como eliminar secciones de una lista:

 a_list[:] = [] # deletes all the items in the list, equivalent to 'del a_list[:]' 

o insertando nuevos valores en medio de una lista:

 a_list[1:1] = [1, 2, 3] # inserts the new values at index 1 in the list 

Sin embargo, con “cortes extendidos”, donde el step no es uno, el iterable debe tener la longitud correcta:

 >>> lst = [1, 2, 3] >>> lst[::2] = [] Traceback (most recent call last): File "", line 1, in  ValueError: attempt to assign sequence of size 0 to extended slice of size 2 

Las principales cosas que son diferentes sobre la asignación de segmentos a a_list son:

  1. a_list ya debe apuntar a un objeto
  2. Ese objeto se modifica, en lugar de apuntar a_list a un nuevo objeto
  3. Ese objeto debe admitir __setitem__ con un índice de __setitem__
  4. El objeto de la derecha debe soportar iteración.
  5. No se apunta ningún nombre al objeto a la derecha. Si no hay otras referencias a él (como cuando se trata de un literal como en su ejemplo), será una referencia que se haya contabilizado después de que se complete la iteración.

¡La diferencia es bastante grande! En

 a_list[:] = ['foo', 'bar'] 

Se modifica una lista existente que estaba vinculada al nombre a_list . Por otra parte,

 a_list = ['foo', 'bar'] 

asigna una nueva lista al nombre a_list .

Tal vez esto ayude:

 a = a_list = ['foo', 'bar'] # another name for the same list a_list = ['x', 'y'] # reassigns the name a_list print a # still the original list a = a_list = ['foo', 'bar'] a_list[:] = ['x', 'y'] # changes the existing list bound to a print a # a changed too since you changed the object 

Al asignar a a_list[:] , a_list sigue a_list referencia al mismo objeto de lista, con los contenidos modificados. Al asignar a a_list , a_list ahora hace referencia a un nuevo objeto de lista.

Echa un vistazo a su id :

 >>> a_list = [] >>> id(a_list) 32092040 >>> a_list[:] = ['foo', 'bar'] >>> id(a_list) 32092040 >>> a_list = ['foo', 'bar'] >>> id(a_list) 35465096 

Como puede ver, su id no cambia con la versión de asignación de segmento.


La diferencia entre los dos podría resultar en un resultado bastante diferente, por ejemplo, cuando la lista es un parámetro de función:

 def foo(a_list): a_list[:] = ['foo', 'bar'] a = ['original'] foo(a) print(a) 

Con esto, a se modifica, pero si en su lugar se a_list = ['foo', 'bar'] , a sigue siendo su valor original.