Question

Je suis un grand fan de la de ... autre syntaxe de Python - il est étonnant de constater à quelle fréquence il est applicable et à quel point il peut simplifier le code.

Cependant, je n’ai pas trouvé de bonne façon de l’utiliser dans un générateur, par exemple:

def iterate(i):
    for value in i:
        yield value
    else:
        print 'i is empty'

Dans l'exemple ci-dessus, j'aimerais que l'instruction print ne soit exécutée que si i est vide. Cependant, comme else ne respecte que break et return , il est toujours exécuté, quelle que soit la longueur de i .

S'il est impossible d'utiliser pour ... else de cette manière, quelle est la meilleure approche à suivre pour que l'instruction print ne soit exécutée que si rien n'est généré?

Était-ce utile?

La solution

Vous cassez la définition d'un générateur, qui devrait générer une exception StopIteration à la fin de l'itération (qui est automatiquement gérée par une instruction return dans une fonction de générateur)

Donc:

def iterate(i):
    for value in i:
        yield value
    return

Il est préférable de laisser le code appelant gérer le cas d'un itérateur vide:

count = 0
for value in iterate(range([])):
    print value
    count += 1
else:
    if count == 0:
        print "list was empty"

Peut-être une façon plus propre de faire ce qui précède, mais cela devrait fonctionner correctement et ne tombe pas dans les pièges habituels consistant à "traiter un itérateur comme une liste", ci-dessous.

Autres conseils

Il y a plusieurs façons de le faire. Vous pouvez toujours utiliser directement Iterator :

def iterate(i):
    try:
        i_iter = iter(i)
        next = i_iter.next()
    except StopIteration:
        print 'i is empty'
        return

    while True:
        yield next
        next = i_iter.next()

Mais si vous savez plus à quoi vous attendre de l'argument i , vous pouvez être plus concis:

def iterate(i):
    if i:  # or if len(i) == 0
        for next in i:
            yield next
    else:
        print 'i is empty'
        raise StopIteration()

Résumant certaines des réponses précédentes, le problème pourrait être résolu comme suit:

def iterate(i):
    empty = True
    for value in i:
        yield value
        empty = False

    if empty:
        print "empty"

donc il n'y a vraiment pas de "autre" clause concernée.

Comme vous le constatez, for..else détecte uniquement une rupture . Cela s'applique donc uniquement lorsque vous recherchez quelque chose, puis arrêtez .

Cela ne s'applique pas à votre objectif, non pas parce que c'est un générateur, mais parce que vous voulez traiter tous les éléments, sans vous arrêter (parce que vous voulez tous les céder, mais ce n'est pas le but).

Donc générateur ou pas, vous avez vraiment besoin d’un booléen, comme dans la solution de Ber.

  
    

S'il est impossible d'utiliser pour ... autrement de cette manière, quelle est la meilleure approche pour que l'instruction print ne soit exécutée que si rien n'est généré?

  

Je peux penser au maximum:


>>> empty = True
>>> for i in [1,2]:
...     empty = False
... if empty:
...     print 'empty'
...
>>>
>>>
>>> empty = True
>>> for i in []:
...     empty = False
... if empty:
...    print 'empty'
...
empty
>>>

Qu'en est-il simple si-sinon?

def iterate(i):
    if len(i) == 0: print 'i is empty'
    else:
        for value in i:
            yield value
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top