Pourquoi le découpage de sous-chaînes avec un index hors de portée fonctionne-t-il?

88

Pourquoi n'entraîne pas 'example'[999:9999]d'erreur? Depuis 'example'[9], quelle est la motivation derrière cela?

À partir de ce comportement, je peux supposer que 'example'[3], essentiellement / en interne, ce n'est pas la même chose que 'example'[3:4], même si les deux aboutissent à la même 'm'chaîne.

ijverig
la source
17
[999:9999]n'est pas un index, c'est une tranche et a une sémantique différente. Extrait de l'intro de python: "Les indices de tranche dégénérée sont gérés avec élégance: un index trop grand est remplacé par la taille de la chaîne, une limite supérieure plus petite que la limite inférieure renvoie une chaîne vide."
Wooble
2
@Wooble c'est la vraie réponse
jondavidjohn
2
@Wooble Et savez-vous pourquoi c'est comme ça? Merci pour la clarification.
ijverig
Pourquoi? Il faudrait demander à Guido, mais je pense que c'est élégant de pouvoir supposer qu'une tranche est toujours le même type de séquence que la séquence originale, moi-même.
Wooble
1
@Lapinot oui j'ai écrit du code qui dépend de ce comportement. Malheureusement, je ne me souviens pas du code exact, donc je ne peux pas vous dire pourquoi. Probablement lié aux sous-chaînes; obtenir une chaîne vide peut parfois être exactement ce que vous voulez.
Mark Ransom

Réponses:

68

Tu as raison! 'example'[3:4]et 'example'[3]sont fondamentalement différents, et le découpage en dehors des limites d'une séquence (au moins pour les éléments intégrés) ne provoque pas d'erreur.

Cela peut paraître surprenant au début, mais c'est logique quand on y pense. L'indexation renvoie un seul élément, mais le découpage renvoie une sous-séquence d'éléments. Ainsi, lorsque vous essayez d'indexer une valeur inexistante, il n'y a rien à retourner. Mais lorsque vous découpez une séquence en dehors des limites, vous pouvez toujours renvoyer une séquence vide.

Une partie de ce qui est déroutant ici est que les chaînes se comportent un peu différemment des listes. Regardez ce qui se passe lorsque vous faites la même chose sur une liste:

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

Ici, la différence est évidente. Dans le cas des chaînes, les résultats semblent identiques car en Python, il n'existe pas de caractère individuel en dehors d'une chaîne. Un seul caractère est juste une chaîne de 1 caractère.

(Pour la sémantique exacte du découpage en dehors de la plage d'une séquence, voir la réponse de mgilson .)

expéditeur
la source
1
Un index hors de portée aurait pu être renvoyé Noneau lieu d'erreur - c'est la convention Python habituelle lorsque vous n'avez rien à retourner.
Mark Ransom
8
@MarkRansom, c'est vrai; mais retourner Nonedans ce cas rendrait plus difficile la distinction entre un index hors limites et une Nonevaleur à l'intérieur d'une liste. Mais même s'il y avait une solution de contournement pour cela, il me semble clair que renvoyer une séquence vide est la bonne chose à faire lorsqu'on lui donne une tranche hors limites. C'est analogue à la réalisation de l'union de deux ensembles disjoints.
senderle
Juste pour être clair, je n'ai pas dit que vous aviez tort. Je vois votre point sur les Nonevaleurs dans une liste.
Mark Ransom
1
@MarkRansom, je sais - désolé si j'avais l'air sur la défensive. Vraiment, je voulais juste une excuse pour faire référence à la théorie des ensembles :).
senderle
4
Oh, sauf que j'ai dit «union» au lieu de «intersection».
senderle
31

Pour ajouter une réponse qui pointe vers une section robuste de la documentation :

Étant donné une expression de tranche comme s[i:j:k],

La tranche de s de i à j avec l'étape k est définie comme la séquence d'éléments avec un index x = i + n*ktel que 0 <= n < (j-i)/k. En d' autres termes, les indices sont i, i+k, i+2*k, i+3*ket ainsi de suite, l' arrêt lorsque j est atteint (mais jamais compris j ). Lorsque k est positif, i et j sont réduits à len(s)s'ils sont plus grands

si vous écrivez s[999:9999], python revient s[len(s):len(s)]depuis len(s) < 999et votre étape est positive ( 1- la valeur par défaut).

mgilson
la source
Vraisemblablement quand kest-il positif, iet jest-il également augmenté jusqu'à -len(s)quand ils sont moindres? egs = 'bac'; s[-100:2] == s[-len(s):2]
Chris_Rands
@Chris_Rands Quand kest positif, Python sera mis à l'échelle iet jpour qu'ils correspondent aux limites de la séquence. Dans votre exemple, s[-100:2] == s[0:2]( == s[-len(s):2], au fait). De même, s[-100:100] == s[0:2].
tylerc0816
Bien, merci. C'est une meilleure réponse au commentaire de @ speedplane ci-dessus.
senderle
8

Le découpage n'est pas vérifié par les limites des types intégrés. Et bien que vos deux exemples semblent avoir le même résultat, ils fonctionnent différemment; essayez-les plutôt avec une liste.

Ignacio Vazquez-Abrams
la source