Использование для ... 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