length index python string slice

python - index - Cómo explicar el reverso de una secuencia por notación de corte a



string python (7)

Del tutorial de python.org

Los índices de corte tienen valores predeterminados útiles; un primer índice omitido por defecto es cero, un segundo índice omitido por defecto al tamaño de la cadena que se corta.

>>> a = "hello" >>> print(a[::-1]) olleh

Como dice el tutorial, a[::-1] debería ser igual a a[0:5:-1]

pero a[0:5:-1] está vacío de la siguiente manera:

>>> print(len(a[0:5:-1])) 0

La pregunta no es un duplicado de explain-slice-notation . Esa pregunta es sobre el uso general de cortar en python.


Creo que los documentos son quizás un poco engañosos sobre esto, pero los argumentos opcionales de segmentación si se omiten son los mismos que usar None :

>>> a = "hello" >>> a[::-1] ''olleh'' >>> a[None:None:-1] ''olleh''

Puede ver que estos 2 segmentos anteriores son idénticos al código de bytes CPython:

>>> import dis >>> dis.dis(''a[::-1]'') # or dis.dis(''a[None:None:-1]'') 1 0 LOAD_NAME 0 (a) 3 LOAD_CONST 0 (None) 6 LOAD_CONST 0 (None) 9 LOAD_CONST 2 (-1) 12 BUILD_SLICE 3 15 BINARY_SUBSCR 16 RETURN_VALUE

Para un step negativo, los valores sustituidos para None son len(a) - 1 para el start y -len(a) - 1 para el end :

>>> a[len(a)-1:-len(a)-1:-1] ''olleh'' >>> a[4:-6:-1] ''olleh'' >>> a[-1:-6:-1] ''olleh''

Esto puede ayudarlo a visualizarlo:

h e l l o 0 1 2 3 4 5 -6 -5 -4 -3 -2 -1


Estás confundido con el comportamiento de los pasos. Para obtener el mismo resultado, lo que puede hacer es:

a[0:5][::-1] ''olleh''

De hecho, los pasos quieren "dar vueltas" hacia atrás en su caso, pero están limitando su movimiento llamando a a[0:5:-1] .


Los documentos simplemente no son correctos acerca de los valores predeterminados, como lo ha señalado. Sin embargo, son consistentes aparte de ese error menor. Puede ver los documentos a los que me refiero aquí: docs.python.org/3/library/…

Tenga en cuenta que el comportamiento es, por definición, correcto según los documentos:

El segmento de s de i a j con el paso k se define como la secuencia de elementos con índice x = i + n * k de modo que 0 <= n <(ji) / k. En otras palabras, los índices son i, i + k, i + 2 * k, i + 3 * k y así sucesivamente, deteniéndose cuando se alcanza j (pero nunca incluyendo j).

Cuando tu lo hagas:

>>> a = "hello" >>> y = a[0:5:-1]

tenemos que i == 0 , j == 5 k == -1 . Entonces, estamos tomando elementos en el índice x = i + n*k para n comienza en 0 y sube a (ji)/k . Sin embargo, observe que (ji)/k == (5-0)/-1 == -5 . No hay n tal que 0 <= n < -5 , por lo que obtienes la cadena vacía:

>>> y ''''

Haga a[start:stop][::step] cuando tenga dudas (casi siempre es lo que queremos)

Casi siempre ocurre que cuando pasas un paso negativo a algo como x[start:stop:step] , lo que quieres que suceda es que la subselección ocurra primero y luego retroceda step (es decir, generalmente queremos x[start:stop][::step] .

Además, para agregar a la confusión, resulta ser el caso que

x[start:stop:step] == x[start:stop][::step]

si step > 0 . Por ejemplo:

>>> x = list(range(10)) >>> x [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> x[2:6:2] [2, 4] >>> x[2:6][::2] [2, 4] >>> x[1:10][::3] [1, 4, 7] >>> x[1:10:3] [1, 4, 7]

Desafortunadamente, esto no se cumple cuando el step < 0 , aunque es tentador pensar que debería.

Después de ser quemado por esto un par de veces, me di cuenta de que es más seguro hacer siempre la cláusula de paso después de realizar el start:stop corte. Así que casi siempre empiezo con y = x[start:stop][::step] , al menos al crear prototipos o crear un nuevo módulo donde la corrección / legibilidad es la principal preocupación. Esto es menos eficaz que hacer una sola porción, pero si el rendimiento es un problema, puede hacer lo menos legible:

y = x[start:stop:step] if step > 0 else x[stop:start:step]

HTH.


Notará que el argumento del tercer segmento, el step , no se presenta en la parte del tutorial que citó. Ese fragmento en particular supone un paso positivo.

Cuando agrega la posibilidad de un paso negativo, el comportamiento es bastante intuitivo. Un parámetro de start vacío se refiere a cualquier final de la secuencia en el que uno comenzaría a recorrer toda la secuencia en la dirección indicada por el valor del step . En otras palabras, se refiere al índice más bajo (para contar hacia arriba) si tiene un paso positivo, y al índice más alto (para contar hacia atrás) si tiene un paso negativo. Del mismo modo, un parámetro end vacío se refiere a cualquier extremo de la secuencia en el que uno terminaría después de pasar en la dirección apropiada.


Para el corte de Python para una secuencia [inicio: parada: paso] , se han derivado estas reglas:

  1. inicio: detener = inicio: detener: 1
  2. inicio: detener: (+ o -) paso - Significa al atravesar saltar elementos N en la secuencia. Sin embargo, (-) indica un recorrido hacia atrás
  3. Recuerde, la posición del último elemento en secuencia es -1, y la anterior es -2, y así sucesivamente.

# start: stop: + paso Reglas

  1. Siempre atravesar hacia adelante
  2. Siempre comience desde el comienzo de la secuencia, ya que es un paso positivo (hacia adelante)
  3. Comience en la posición solicitada, pare en la posición solicitada pero excluya la posición de parada del artículo
  4. Inicio predeterminado: si no se proporciona el inicio, comience en 0
  5. Parada predeterminada: si no se proporciona la parada, significa hasta el final de la secuencia, incluido el último valor
  6. Si no se puede alcanzar el elemento en la posición de parada (el elemento está más allá del final del recorrido de la secuencia), el corte no devuelve nada

# start: stop: -step Rules

  1. Siempre atravesar en reversa
  2. Si se proporciona la posición de inicio, comience desde allí, pero atraviese en reversa (es un paso atrás)
  3. Si se proporciona detención, deje de atravesar allí pero excluya esto
  4. Inicio predeterminado: si no se proporciona la posición de inicio, la posición de inicio es la última posición de la secuencia (desde el cruce negativo)
  5. Parada predeterminada: si no se proporciona la parada, es el comienzo de la lista (posición 0)
  6. Si no se puede alcanzar el elemento en la posición de parada (el elemento está más allá del final del recorrido de la secuencia), el corte no devuelve nada

Todo lo que hace es slice . Usted escoge. comenzar, parar y dar un paso, así que básicamente estás diciendo que debería comenzar desde el principio hasta el principio pero retroceder (-1).

Si lo haces con -2, saltará letras:

>>> a[::-2] ''olh''

Al hacer [0:5:-1] estás comenzando en la primera letra y regresando directamente a 5 y así se detendrá. solo si intenta [-1::-1] podrá ir correctamente al principio siguiendo los pasos del negativo 1.

Editar para responder comentarios

Como se señaló la documentación dice

un segundo índice omitido por defecto es el tamaño de la cadena que se corta.

Supongamos que tenemos str con len(str) = 5 . Cuando corta la cadena y omite, omita, el segundo número predeterminado es la longitud de la cadena que se corta, en este caso - 5. es decir str[1:] == str[1:5] , str[2:] == str[2:5] . La oración se refiere a la longitud del objeto original y no al objeto recién cortado.

Además, esta respuesta es genial


a[0:5:-1] no tiene mucho sentido, ya que cuando usa esta notación los índices significan: a[start:end:step] . Cuando utiliza un paso negativo, su valor final debe estar en una posición "anterior" a su valor inicial.