Python: une itération sur une liste non vide sans si la clause arrive vide. Pourquoi?
-
22-08-2019 - |
Question
Comment un itérateur sur une séquence non vide, sans filtrage ni agrégation (sum()
, etc.), rien? Rendement
Prenons un exemple simple:
sequence = ['a', 'b', 'c']
list((el, ord(el)) for el in sequence)
On obtient ainsi [('a', 97), ('b', 98), ('c', 99)]
comme prévu.
Maintenant, juste échanger l'ord(el)
pour une expression qui prend la première valeur de certains générateur utilisant (...).next()
- pardonnez l'exemple artificiel:
def odd_integers_up_to_length(str):
return (x for x in xrange(len(str)) if x%2==1)
list((el, odd_integers_up_to_length(el).next()) for el in sequence)
Cela donne []
. Ouais, liste vide. Pas ('a',
stuff)
tuples. Rien.
Mais nous ne sommes pas le filtrage ou l'agrégation ou la réduction. Une expression de la génératrice sur les objets n
sans filtrage ou d'agrégation doit céder les objets n
, à droite? Que se passe-t-il?
La solution
odd_integers_up_to_length(el).next()
soulèvera StopIteration, qui n'y est pas pris, mais il est pris pour l'expression du générateur en son sein, arrêter sans jamais rien céder.
regardez la première itération, lorsque la valeur est 'a':
>>> odd_integers_up_to_length('a').next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
Autres conseils
Ce qui se passe est que l'appel de next()
génère une exception StopIteration
, qui bouillonne la pile à l'expression de la génératrice externe et arrête que itération.
A StopIteration
est la voie normale pour un itérateur pour signaler qu'il est fait. En général, nous ne voyons pas, parce que généralement l'appel next()
se produit dans une construction qui consomme le iterator, par exemple for x in iterator
ou sum(iterator)
. Mais quand nous appelons next()
directement, nous sommes responsables pour prendre le StopIteration
. Ne pas faire ressorts si une fuite dans l'abstraction, ce qui conduit ici à un comportement inattendu dans l'itération externe.
La leçon, je suppose: attention sur les appels directs à next()
str est un mot-clé réservé, vous devez nommer différemment votre variable
Je suis également conseiller sur la prochaine
>>> seq=['a','b','c']
>>> list((el,4) for el in seq)
[('a',4), ('b',4), ('c',4)]
Il est list
ne vous donne pas mal à ici ...