python python-3.x sequence slice range-checking

¿Por qué Python permite índices de corte fuera de rango para las secuencias?



python-3.x sequence (2)

Así que me encontré con lo que me parece una característica extraña de Python y quería una aclaración al respecto.

La siguiente manipulación de matrices tiene algo de sentido:

p = [1,2,3] p[3:] = [4] p = [1,2,3,4]

Me imagino que en realidad es solo agregar este valor al final, ¿correcto?
¿Por qué puedo hacer esto, sin embargo?

p[20:22] = [5,6] p = [1,2,3,4,5,6]

Y más aún esto:

p[20:100] = [7,8] p = [1,2,3,4,5,6,7,8]

Esto simplemente parece una lógica errónea. Parece que esto debería lanzar un error!

Alguna explicacion
-¿Es solo una cosa extraña que Python hace?
-¿Hay algún propósito?
-O estoy pensando en esto de manera equivocada?


Parte de la pregunta sobre índices fuera de rango.

La lógica de corte corta automáticamente los índices a la longitud de la secuencia.

Permitir que los índices de corte se extiendan más allá de los puntos finales se hizo por conveniencia. Sería un dolor tener que revisar cada expresión y luego ajustar los límites manualmente, por lo que Python lo hace por ti.

Considere el caso de uso de querer mostrar no más de los primeros 50 caracteres de un mensaje de texto.

La manera fácil (lo que Python hace ahora):

preview = msg[:50]

O de la manera difícil (haz el límite te verifica):

n = len(msg) preview = msg[:50] if n > 50 else msg

Implementar manualmente esa lógica para el ajuste de los puntos finales sería fácil de olvidar, sería fácil equivocarse (actualizar los 50 en dos lugares), sería prolijo y sería lento. Python mueve esa lógica a sus elementos internos, donde es sucinta, automática, rápida y correcta. Esta es una de las razones por las que amo Python :-)

Parte de la pregunta con respecto a la desajuste de la longitud de las asignaciones de la longitud de entrada

El OP también quiso saber la razón para permitir asignaciones como p[20:100] = [7,8] donde el objetivo de la asignación tiene una longitud diferente (80) que la longitud de los datos de reemplazo (2).

Es más fácil ver la motivación por una analogía con cuerdas. Considere, "five little monkeys".replace("little", "humongous") . Tenga en cuenta que el objetivo "pequeño" tiene solo seis letras y "enorme" tiene nueve. Podemos hacer lo mismo con las listas:

>>> s = list("five little monkeys") >>> i = s.index(''l'') >>> n = len(''little'') >>> s[i : i+n ] = list("humongous") >>> ''''.join(s) ''five humongous monkeys''

Todo esto se reduce a la conveniencia.

Antes de la introducción de los métodos copy () y clear () , estos solían ser expresiones populares populares:

s[:] = [] # clear a list t = u[:] # copy a list

Incluso ahora, usamos esto para actualizar las listas cuando filtramos:

s[:] = [x for x in s if not math.isnan(x)] # filter-out NaN values

Espero que estos ejemplos prácticos ofrezcan una buena perspectiva de por qué el corte en rodajas funciona como lo hace.


La documentation tiene su respuesta:

s[i:j] : segmento de s de i a j (nota (4))

(4) La porción de s de i a j se define como la secuencia de elementos con índice k tal que i <= k < j . Si i o j es mayor que len(s) , use len(s) . Si se omite i o None , use 0 . Si j se omite o None , use len(s) . Si i es mayor o igual que j , la división está vacía.

La documentación de IndexError confirma este comportamiento:

excepción IndexError

Se genera cuando un subíndice de secuencia está fuera de rango. (Los índices de corte se truncan silenciosamente para caer en el rango permitido; si un índice no es un número entero, TypeError se eleva).

Esencialmente, cosas como p[20:100] se están reduciendo a p[len(p):len(p] . p[len(p):len(p] es una porción vacía al final de la lista, y asignando una lista a la misma modificará el final de la lista para contener dicha lista. Por lo tanto, funciona como agregar / extender la lista original.

Este comportamiento es el mismo que sucede cuando asigna una lista a un sector vacío en cualquier lugar de la lista original. Por ejemplo:

In [1]: p = [1, 2, 3, 4] In [2]: p[2:2] = [42, 42, 42] In [3]: p Out[3]: [1, 2, 42, 42, 42, 3, 4]