web-dev-qa-db-fra.com

Pourquoi les itérateurs de Python déclenchent une exception?

Voici la syntaxe des itérateurs dans Java (syntaxe quelque peu similaire en C #):

Iterator it = sequence.iterator();

while (it.hasNext()) {
    System.out.println(it.next());
}

Ce qui est logique. Voici la syntaxe équivalente en Python:

it = iter(sequence)
while True:
    try:
        value = it.next() 
    except StopIteration:
        break
    print(value)

Je pensais que les exceptions n'étaient censées être utilisées que dans des circonstances exceptionnelles.

Pourquoi Python utilise-t-il des exceptions pour arrêter l'itération?

48

Il existe une façon très pythonique d'écrire cette expression sans écrire explicitement un bloc try-except pour un StopIteration:

# some_iterable is some collection that can be iterated over
# e.g., a list, sequence, dict, set, itertools.combination(...)

for value in some_iterable:
    print(value)

Vous pouvez lire les PEP pertinents 234255 si vous voulez en savoir plus sur les raisons pour lesquelles StopIteration a été introduit et la logique derrière les itérateurs.

Un principe général dans python est d'avoir une façon de faire quelque chose (voir import this), et de préférence son beau, explicite, lisible et simple, que la méthode Pythonic satisfait. Votre code équivalent est uniquement nécessaire car python ne donne pas aux itérateurs une fonction membre hasNext; préférant que les gens parcourent simplement les itérateurs directement (et si vous devez faire autre chose) pour essayer de le lire et attraper une exception).

Cette capture automatique d'une exception StopIteration à la fin d'un itérateur est logique et est un analogue de la EOFError levée si vous lisez après une fin de fichier.

50
dr jimbob

La raison pour laquelle python utilise une exception pour arrêter une itération est documentée dans PEP 234 :

Il a été demandé si une exception pour signaler la fin de l'itération n'est pas trop chère. Plusieurs alternatives pour l'exception StopIteration ont été proposées: une valeur spéciale End pour signaler la fin, une fonction end () pour tester si l'itérateur est terminé, même en réutilisant l'exception IndexError.

  • Une valeur spéciale a le problème que si une séquence contient jamais cette valeur spéciale, une boucle sur cette séquence se terminera prématurément sans aucun avertissement. Si l'expérience avec les chaînes C à terminaison nulle ne nous a pas appris les problèmes que cela peut causer, imaginez le problème qu'un outil d'introspection Python aurait itéré sur une liste de tous les noms intégrés, en supposant que la valeur spéciale End était un nom intégré!

  • L'appel d'une fonction end () nécessiterait deux appels par itération. Deux appels coûtent beaucoup plus cher qu'un appel plus un test d'exception. Surtout le temps critique pour la boucle peut tester très bon marché pour une exception.

  • La réutilisation d'IndexError peut être source de confusion car il peut s'agir d'une véritable erreur, qui serait masquée en mettant fin prématurément à la boucle.

Remarque: la façon idiomatique python de faire une boucle sur une séquence est comme ceci:

for value in sequence:
    print (value)
28
lesmana

C'est une différence de philosophie. La philosophie de conception Pythonic est EAFP :

Plus facile de demander pardon que la permission. Ce style de codage commun Python suppose l'existence de clés ou d'attributs valides et intercepte les exceptions si l'hypothèse se révèle fausse. Ce style propre et rapide se caractérise par la présence de nombreux try et except instructions. La technique contraste avec le style [~ # ~] lbyl [~ # ~] commun à de nombreuses autres langues telles que C ...

20
Charles E. Grant

C'est juste que l'implémentation Java a une méthode hasNext() afin que vous puissiez vérifier si un itérateur est vide avant d'effectuer une next(). Lorsque vous appelez next() sur un Java sans élément restant, un NoSuchElementException est levé .

Donc, efficacement, vous pouvez faire un try..catch en Java comme le try..except en Python. Et oui, selon une réponse précédente, la philosophie est très important dans le monde Pythonique.

7
yati sagade