python - operator - ¿Cuál es la diferencia entre la asignación de división que divide toda la lista y la asignación directa?
slice operator in python (3)
Veo en muchos lugares el uso de la asignación de sectores para list
s. Puedo 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'']
?
¡La diferencia es bastante grande! En
a_list[:] = [''foo'', ''bar'']
Usted 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
a_list = [''foo'', ''bar'']
Crea una nueva list
en la memoria y señala el nombre a_list
en ella. Es irrelevante a lo que a_list
apuntaba antes.
a_list[:] = [''foo'', ''bar'']
Llama al método a_list
objeto a_list
con un sector como el índice, y una nueva list
creada en la memoria como el valor.
__setitem__
evalúa el sector para descubrir qué índices representa y lo llama al valor que se pasó. Luego itera sobre el objeto, estableciendo cada índice dentro del rango especificado por el sector al siguiente valor del objeto. Para las list
, si el rango especificado por el sector no es de la misma longitud que el slice
iterativo, la list
cambia de tamaño. 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 el medio de una lista:
a_list[1:1] = [1, 2, 3] # inserts the new values at index 1 in the list
Sin embargo, con "sectores 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 "<interactive input>", line 1, in <module>
ValueError: attempt to assign sequence of size 0 to extended slice of size 2
Las principales cosas que son diferentes acerca de la asignación de a_list
a una a_list
son:
-
a_list
ya debe apuntar a un objeto - Ese objeto se modifica, en lugar de apuntar
a_list
a un nuevo objeto - Ese objeto debe ser compatible con
__setitem__
con un índice de sector - El objeto de la derecha debe ser compatible con la iteración
- Ningún nombre apunta al objeto a la derecha. Si no hay otras referencias a la misma (como cuando es literal como en su ejemplo), será referencia contada fuera de existencia después de que se complete la iteración.
Al asignar a a_list[:]
, a_list
sigue a_list
referencia al mismo objeto de la lista, con los contenidos modificados. Al asignar a a_list
, a_list
ahora hace referencia a un nuevo objeto de lista.
Mira 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 división.
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 a_list = [''foo'', ''bar'']
se usa en su lugar, a
permanece su valor original.