[Python] Pourquoi les tranches ne provoquent pas d'erreurs d'index

introduction

C'est une histoire bien connue (j'oublie souvent) que peu importe la taille ou la petite spécification d'un nombre dans une tranche Python, une erreur d'index ne se produit pas, mais la raison en est "** Il le gère bien en interne. ** «Je pensais que je ne pouvais pas trouver un article en japonais expliquant ce qui précède, alors j'ai décidé de l'écrire comme une industrie de l'écart.

Dans cet article, j'expliquerai le thème du sujet sous deux angles: ** idée ** et ** implémentation . J'espère me débarrasser de la maladie des personnes qui sont novices en Python et qui pensent que " Erreur d'indexation lors de l'extraction d'un élément spécifique May est considérée comme une tranche, mais ce n'est pas une tranche **". Je vais.

De plus, étant donné que l'auteur lui-même est inexpérimenté, je vous serais reconnaissant de bien vouloir signaler toute inexactitude dans les expressions pour une étude ultérieure.

Que fait une tranche (en premier lieu)?

Cette section correspond à la partie idée du tranchage. Même dans le document officiel, «qu'est-ce qu'une tranche» n'est pas écrit clairement (semble-t-il), mais c'est frustrant, mais il y a pour l'instant l'explication suivante.

--Remarque sur s [i: j]

Une tranche de> s de i à j est définie comme une séquence d'éléments avec un indice k tel que i <= k <j.

--Note sur s [i: j: k]

La "tranche de i à j avec étapes k"> s est constituée d'éléments avec un index x = i + n * k (où n est tout entier qui satisfait 0 <= n <(ji) / k). Défini comme une séquence.

Intégré - Documentation Python 3.8.5

Vous pouvez le comprendre si vous le lisez correctement, mais c'est un peu ennuyeux.

Si vous extrayez uniquement ce dont vous avez besoin maintenant, le découpage signifie-t-il que "créer une nouvelle ** séquence ** composée de ** éléments ** correspondant à l'index spécifié ** à partir de la séquence d'origine"?

(Une séquence est un type de données tel que liste, taple, plage, chaîne, chaîne d'octets, etc.)

Voici une citation de Stack Overflow expliquant pourquoi c'est important.

Indexing returns a single item, but slicing returns a subsequence of items. So when you try to index a nonexistent value, there's nothing to return. But when you slice a sequence outside of bounds, you can still return an empty sequence.

https://stackoverflow.com/a/9490148

En d'autres termes

  1. L'extraction d'élément renvoie un seul élément, mais les tranches renvoient une séquence.
  2. Si vous spécifiez un index qui n'existe pas dans l'extraction d'éléments, il n'y a rien à renvoyer, mais s'il s'agit d'une séquence, vous pouvez renvoyer une séquence vide.

Je dis ça. J'ai mentionné 1 ci-dessus, donc je ne pense pas qu'il soit nécessaire de l'expliquer, mais qu'en est-il de 2?

En bref, «[0,1,2] [3]» est ** une erreur car il n'y a pas de valeur de retour **, mais «[0,1,2] [3:]» est un élément correspondant à l'indice 3 ou supérieur. S'il n'y a pas de ** liste vide, [] peut être renvoyée comme valeur de retour, il n'est donc pas nécessaire de faire une erreur **.

Cela dit, les personnes d'Antoinette (y compris l'auteur) lisant ceci ont dit: "** Si vous devez avoir une valeur de retour, vous pouvez renvoyer None avec [0,1,2] [3]. Vous pourriez penser: "Ce n'est pas bon **".

Cependant, dans ce cas, il est possible de déterminer si ** [0,1,2] [3] renvoie None ou [0,1,2, None] [3] renvoie None ** J'ai encore besoin d'une erreur d'index car cela devient plus difficile (et l'a gentiment complétée dans la suite de la citation précédente).

L'explication a peut-être été un peu redondante, mais la conclusion était que l'erreur "** slice peut retourner une séquence vide même s'il n'y a pas d'élément correspondant **" ne se produit pas.

(Jabashi: Cela me donne envie d'utiliser des termes comme "sous-ensemble / sous-chaîne" et "ensemble vide", mais quand je dis "ensemble", ignorez l'élément de type séquence "ordre". Après tout, il n'y a pas d'autre choix que de l'expliquer comme le document officiel.)

La véritable identité du «bon sentiment»

Cette section correspond à la partie implémentation de la tranche.

Comment gérez-vous des opérations comme «[P, y, t, h, o, n] [100: 200]» d'une «bonne manière»? La réponse est une continuation de la citation du document officiel dans la section précédente. Il est caché dans la pièce.

--Remarque sur s [i: j]

Si> i ou j est supérieur à len (s), utilisez len (s). Si i est omis ou Aucun, utilisez 0. Si j est omis ou None, utilisez len (s). Si i est supérieur ou égal à j, la tranche sera une séquence vide.

En d'autres termes, dans «[P, y, t, h, o, n] [100: 200]», «len (s)» est utilisé parce que «i» et «j» sont tous deux plus grands que «len (s)». Alors, ʻi (= len (s))> = j (= len (s)) `tient, donc il est jugé qu'une séquence vide est retournée.

[Les tranches sont également indexées en interne](https://qiita.com/tanuk1647/items/276d2be36f5abb8ea52e#How les tranches sont converties en index), donc elles sont plus grandes que len (s) Les nombres sont convertis à l'avance. Lorsque «step» est spécifié, le même traitement est essentiellement effectué.

Enfin, je vais vous donner une référence sur la façon dont le traitement ici est implémenté dans CPython. Je ne suis pas fort en C non plus, donc je pense que vous devriez le regarder dans la mesure où "Ah, c'est définitivement écrit comme ça" (aussi dans le code source / * c'est plus difficile à comprendre que vous ne le pourriez Il dit penser * / ).

(Dans cette section, nous avons expliqué le cas où step n'est pas utilisé, mais dans le code de devis, c'est le processus lorsque step est utilisé. Je ne sais pas.)

sliceobject.c


defstop = *step < 0 ? -1 : length;
...
if (r->stop == Py_None) {
    *stop = defstop;
}
...
if ((*step < 0 && *stop >= *start)
    || (*step > 0 && *start >= *stop)) {
    *slicelength = 0;

cpython: 3a1db0d2747e Objects/sliceobject.c

Conclusion

Le tranchage est pratique.

Merci d'avoir regardé jusqu'à la fin.

Site de référence

Intégré - Documentation Python 3.8.5 [Python] Résumé du fonctionnement de la tranche --Qiita python - Why does substring slicing with index out of range work? - Stack Overflow string - Why python's list slicing doesn't produce index out of bound error? - Stack Overflow

Recommended Posts

[Python] Pourquoi les tranches ne provoquent pas d'erreurs d'index
Erreur Python non implémentée
Entrée clé qui n'attend pas l'entrée clé en Python
BigQuery - Si vous obtenez une erreur Reason: responseTooLarge en Python
Mesurez l'indice BMI en Python.
Note de prise en charge des erreurs Python: "... ne prend pas en charge l'argument 0 de type float ..."
la version de python ne change pas
python> n'inclut pas les lettres mm> si "mm" pas dans le texte: / print "sans mm"
[Python] Erreur de nom: le nom'urlparse 'n'est pas défini
Le problème de chemin ne se produit pas sur debian-linux
Erreur [Python d'instruction matérielle illégale] dans PyMC3
[VScode] Le format autopep8 ne fonctionne pas [Python]
Virtualenv ne fonctionne pas sur Python 3.5 (Windows)
Python / dictionary> setdefault ()> Ajouter si pas dans le dictionnaire
Python> Python n'inclut pas le dernier décalage
tensorflow n'entre pas dans windows + anaconda.
Tkinter n'a pas pu être importé en Python
Dans Ruby, inspect ne remplace pas to_s
Erreur d'importation: aucun module nommé "xxxxxx" dans Python3
Pourquoi ne puis-je pas installer matplotlib avec python! !!
Quelle est la raison pour laquelle l'homme n'affiche pas les commandes de base en japonais?
Correctif lorsque la recherche de texte intégral ne fonctionne pas dans l'environnement local GAE / Python