Je suis curieux de savoir la différence entre l'utilisation de raise StopIteration
et une instruction return
dans les générateurs.
Par exemple, y a-t-il une différence entre ces deux fonctions?
def my_generator0(n):
for i in range(n):
yield i
if i >= 5:
return
def my_generator1(n):
for i in range(n):
yield i
if i >= 5:
raise StopIteration
Je suppose que la façon la plus "Pythonique" de le faire est la deuxième façon (veuillez me corriger si je me trompe), mais pour autant que je puisse voir les deux manières, lever une exception StopIteration
.
Il n'est pas nécessaire d'augmenter explicitement StopIteration
car c'est ce que fait une simple instruction return
pour une fonction de générateur - alors oui, ce sont les mêmes. Mais non, utiliser simplement return
est plus Pythonic.
De: http://docs.python.org/2/reference/simple_stmts.html#the-return-statement (valide pour Python 3.2)
Dans une fonction de générateur, l'instruction return n'est pas autorisée à inclure une expression_list. Dans ce contexte, un retour brut indique que le générateur est terminé et provoquera l'augmentation de StopIteration.
Ou comme le souligne @Bakuriu - la sémantique des générateurs a légèrement changé pour Python 3.3, donc ce qui suit est plus approprié:
Dans une fonction de générateur, l'instruction return indique que le générateur est terminé et provoquera l'augmentation de StopIteration. La valeur renvoyée (le cas échéant) est utilisée comme argument pour construire StopIteration et devient l'attribut StopIteration.value.
À la fin de 2014, return
est correct et raise StopIteration
pour arrêter un générateur est sur un plan d'amortissement. Voir PEP 479 pour plus de détails.
Abstrait
Ce PEP propose une modification des générateurs: lorsque
StopIteration
est élevé dans un générateur, il est remplacé parRuntimeError
. (Plus précisément, cela se produit lorsque l'exception est sur le point de sortir du cadre de pile du générateur.) Comme la modification est incompatible vers l'arrière, la fonctionnalité est initialement introduite à l'aide d'un__future__
déclaration.Acceptation
Ce PEP a été accepté par le BDFL le 22 novembre…
Raisonnement
L'interaction des générateurs et StopIteration est actuellement quelque peu surprenante et peut masquer des bugs obscurs. Une exception inattendue ne doit pas entraîner un comportement subtilement modifié, mais doit provoquer un retraçage bruyant et facilement débogué. Actuellement, StopIteration déclenché accidentellement à l'intérieur d'une fonction de générateur sera interprété comme la fin de l'itération par la construction de boucle entraînant le générateur.
…
C'est vrai, ils sont équivalents sauf que l'un est lisible tandis que l'autre est obscur. Cela remonte à la toute première version des générateurs (PEP 255, sous "Spécification: Retour"), et les améliorations ultérieures de (telles que les coroutines) ne changent rien. yield from
De 3.3 (PEP 380) étend cela à return <expr>
Comme sucre syntaxique pour raise StopIteration(<expr>)
, mais cela ne change pas la signification de return;
.