9

我是 Python 的for...else 语法的忠实拥护者——令人惊讶的是它的适用频率以及简化代码的效率。

但是,我还没有想出在生成器中使用它的好方法,例如:

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

在上面的示例中,我希望仅当为空print时才执行该语句。i但是,else仅考虑breakreturn,它总是被执行,而不管 的长度i

如果不可能以for...else这种方式使用,那么最好的方法是什么,以便print仅在没有产生任何内容时执行该语句?

4

6 回答 6

11

您正在破坏生成器的定义,它应该在迭代完成时引发 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"

可能是执行上述操作的一种更清洁的方法,但这应该可以正常工作,并且不会落入下面任何常见的“将迭代器视为列表”陷阱。

于 2009-03-02T19:32:18.207 回答
5

有几种方法可以做到这一点。你总是可以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()
于 2009-03-02T19:44:40.967 回答
5

总结一些较早的答案,可以这样解决:

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

    if empty:
        print "empty"

所以确实没有涉及“其他”条款。

于 2009-03-02T20:45:06.970 回答
4

如您所述,for..else仅检测到break. 所以它只适用于你寻找东西然后停止的时候。

它不适用于您的目的,不是因为它是生成器,而是因为您想处理所有元素,而不停止(因为您想全部生成它们,但这不是重点)。

不管是否生成器,你真的需要一个布尔值,就像 Ber 的解决方案一样。

于 2009-12-31T13:43:55.440 回答
0

如果无法以这种方式使用 for...else,那么最好的方法是什么,以便仅在没有产生任何内容时执行 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
>>>

于 2009-03-02T20:16:42.263 回答
-2

简单的 if-else 怎么样?

def iterate(i):
    if len(i) == 0: print 'i is empty'
    else:
        for value in i:
            yield value
于 2009-03-02T19:36:27.367 回答