Por que o fatiamento de substring com índice fora do intervalo funciona?

88

Por que não 'example'[999:9999]resulta em erro? Desde então 'example'[9], qual é a motivação por trás disso?

A partir desse comportamento, posso assumir que 'example'[3]é, essencialmente / internamente, diferente de 'example'[3:4], embora ambos resultem na mesma 'm'string.

ijverig
fonte
17
[999:9999]não é um índice, é uma fatia e tem semânticas diferentes. Da introdução do python: "Índices de fatia degenerados são tratados com elegância: um índice muito grande é substituído pelo tamanho da string, um limite superior menor que o limite inferior retorna uma string vazia."
Wooble
2
@Wooble essa é a resposta real
jondavidjohn
2
@Wooble E você sabe por que é assim? Obrigado pelo seu esclarecimento.
ijverig
Por quê? Você teria que perguntar ao Guido, mas acho que é elegante poder assumir que uma fatia é sempre o mesmo tipo de sequência da sequência original, eu mesmo.
Wooble
1
@Lapinot sim, escrevi um código que depende desse comportamento. Infelizmente, não consigo lembrar o código exato, então não posso dizer por quê. Provavelmente tinha a ver com substrings; obter uma string vazia pode ser exatamente o que você deseja às vezes.
Mark Ransom

Respostas:

68

Você está correto! 'example'[3:4]e 'example'[3]são fundamentalmente diferentes, e cortar fora dos limites de uma sequência (pelo menos para integrados) não causa um erro.

Pode ser surpreendente no início, mas faz sentido quando você pensa a respeito. A indexação retorna um único item, mas o fatiamento retorna uma subsequência de itens. Portanto, quando você tenta indexar um valor inexistente, não há nada a retornar. Mas quando você divide uma sequência fora dos limites, ainda pode retornar uma sequência vazia.

Parte do que é confuso aqui é que as strings se comportam de maneira um pouco diferente das listas. Veja o que acontece quando você faz a mesma coisa com uma lista:

>>> [0, 1, 2, 3, 4, 5][3]
3
>>> [0, 1, 2, 3, 4, 5][3:4]
[3]

Aqui, a diferença é óbvia. No caso de strings, os resultados parecem ser idênticos porque em Python não existe um caractere individual fora de uma string. Um único caractere é apenas uma string de 1 caractere.

(Para a semântica exata de fatiar fora do intervalo de uma sequência, consulte a resposta de mgilson .)

remetente
fonte
1
Um índice fora do intervalo poderia ter retornado em Nonevez de um erro - essa é a convenção usual do Python quando você não tem nada para retornar.
Mark Ransom
8
@MarkRansom, isso é verdade; mas retornar Nonenesse caso tornaria mais difícil saber entre um índice fora dos limites e um Nonevalor dentro de uma lista. Mas mesmo que houvesse uma solução alternativa para isso, permanece claro para mim que retornar uma sequência vazia é a coisa certa a se fazer quando é fornecida uma fatia fora dos limites. É análogo a realizar a união de dois conjuntos disjuntos.
remetente
Só para ficar claro, eu não disse que você estava errado. Eu vejo seu ponto sobre Nonevalores em uma lista.
Mark Ransom
1
@MarkRansom, eu sei - desculpe se soei na defensiva. Sério, eu só queria uma desculpa para me referir à teoria dos conjuntos :).
remetente
4
Ah, exceto que eu disse "união" em vez de "interseção".
remetente em
31

Para adicionar uma resposta que aponta para uma seção robusta na documentação :

Dada uma expressão de fatia como s[i:j:k],

A fatia de s de i a j com passo k é definida como a sequência de itens com índice x = i + n*ktal que 0 <= n < (j-i)/k. Em outras palavras, os índices são i, i+k, i+2*k, i+3*ke assim por diante, parando quando j é atingido (mas nunca incluindo j ). Quando k é positivo, i e j são reduzidos para len(s)se forem maiores

se você escrever s[999:9999], python está retornando s[len(s):len(s)]desde então len(s) < 999e seu passo é positivo ( 1- o padrão).

mgilson
fonte
Presumivelmente, quando ké positivo ie jtambém são aumentados para -len(s)quando são menores? por exemplos = 'bac'; s[-100:2] == s[-len(s):2]
Chris_Rands
@Chris_Rands Quando ké positivo, o Python escala ie jde modo a que eles se encaixam os limites da sequência. No seu exemplo, s[-100:2] == s[0:2]( == s[-len(s):2], a propósito). Da mesma forma s[-100:100] == s[0:2],.
tylerc0816 de
Legal, obrigado. Esta é uma resposta melhor ao comentário de @ speedplane acima.
remetente
8

O corte não tem limites verificados pelos tipos internos. E embora ambos os exemplos pareçam ter o mesmo resultado, eles funcionam de forma diferente; experimente-os com uma lista.

Ignacio Vazquez-Abrams
fonte