Использование для ... else в генераторах Python

Я большой поклонник питона for...еще синтаксис - удивительно, как часто он применим и как эффективно он может упростить код.

однако я не придумал хороший способ использовать его в генераторе, например:

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

в приведенном выше примере, я хотел бы print оператор должен выполняться только если i пусто. Однако, как else только уважает break и return, Он всегда выполняется, независимо от длины i.

если это невозможно использовать for...else таким образом, каков наилучший подход к этому, чтобы print инструкция выполняется только тогда, когда ничего не дали?

6 ответов


вы нарушаете определение генератора, который должен вызывать исключение StopIteration при завершении итерации (которое автоматически обрабатывается оператором return в функции генератора)

Так:

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

лучше всего позволить вызывающему коду обрабатывать случай пустого итератора:

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

может быть более чистым способом сделать вышеизложенное, но это должно работать нормально и не попадает ни в один из распространенных "обработки итератора как списка" ловушки внизу.


есть несколько способов сделать это. Вы всегда можете использовать 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()

но если вы знаете больше о том, чего ожидать от аргумента i, вы можете быть более кратким:

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

суммируя некоторые из предыдущих ответов, его можно решить следующим образом:

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

    if empty:
        print "empty"

таким образом, действительно нет предложения "else".


Как вы отмечаете, for..else обнаруживает только break. Так что это применимо только тогда, когда вы ищете что-то, а затем остановка.

это не применимо к вашей цели не потому, что это генератор, но потому что вы хотите обрабатывать все элементы, не останавливаясь (потому что вы хотите дать им все, но это не суть).

Так генератор или нет, вам действительно нужно логическое, как в решении по Бер.


Если это невозможно использовать для...иначе, каков наилучший подход к этому, чтобы оператор print выполнялся только тогда, когда ничего не дается?

максимум, что я могу думать:


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


Как насчет простого if-else?

def iterate(i):
    if len(i) == 0: print 'i is empty'
    else:
        for value in i:
            yield value