Pregunta

Soy un gran fan de de Python para ... la sintaxis de else : es sorprendente la frecuencia con la que se aplica y la eficacia con la que puede simplificar el código.

Sin embargo, no he descubierto una buena forma de usarlo en un generador, por ejemplo:

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

En el ejemplo anterior, me gustaría que la declaración print se ejecute solo si i está vacío. Sin embargo, como else solo respeta break y return , siempre se ejecuta, independientemente de la longitud de i .

Si es imposible usar para ... else de esta manera, ¿cuál es el mejor enfoque para que la declaración print solo se ejecute cuando no se obtiene nada?

¿Fue útil?

Solución

Está rompiendo la definición de un generador, que debería lanzar una excepción StopIteration cuando se complete la iteración (que se maneja automáticamente mediante una declaración de retorno en una función de generador)

Entonces:

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

Es mejor dejar que el código de llamada maneje el caso de un iterador vacío:

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

Podría ser una forma más limpia de hacer lo anterior, pero debería funcionar bien, y no caer en ninguna de las trampas comunes de "tratar un iterador como una lista" a continuación.

Otros consejos

Hay un par de maneras de hacer esto. Siempre se puede usar el Iterator directamente:

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()

Pero si sabe más sobre qué esperar del argumento i , puede ser más conciso:

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

Resumiendo algunas de las respuestas anteriores, podría resolverse así:

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

    if empty:
        print "empty"

así que realmente no hay " else " cláusula involucrada.

Como usted observa, for..else solo detecta un break . Por lo tanto, solo se aplica cuando buscas algo y luego para .

No es aplicable a su propósito, no porque sea un generador, sino porque desea procesar todos los elementos, sin detenerse (porque desea cederlos a todos, pero ese no es el punto).

Generador o no, realmente necesitas un booleano, como en la solución de Ber.

  
    

Si es imposible de usar para ... de otra forma, ¿cuál es el mejor enfoque para que la declaración de impresión solo se ejecute cuando no se obtiene nada?

  

Máximo que puedo pensar:


>>> 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é pasa con simple si-else?

def iterate(i):
    if len(i) == 0: print 'i is empty'
    else:
        for value in i:
            yield value
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top