在Python生成器中使用for ... else

时间:2009-03-02 19:28:10

标签: python syntax for-loop generator yield

我是Python for...else syntax的忠实粉丝 - 令人惊讶的是它的适用频率,以及它如何有效地简化代码。

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

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

在上面的例子中,我希望仅当print为空时才执行i语句。但是,由于else仅尊重breakreturn,因此无论i的长度如何,它始终都会执行。

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

6 个答案:

答案 0 :(得分: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"

可能是一种更干净的方式来做上述事情,但这应该工作正常,并且不属于任何常见的“处理像列表中的迭代器”陷阱。

答案 1 :(得分: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()

答案 2 :(得分:3)

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

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

    if empty:
        print "empty"

因此确实没有涉及“其他”条款。

答案 3 :(得分:3)

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

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

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

答案 4 :(得分:0)

  
    

如果不能以这种方式使用... 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
>>>

答案 5 :(得分:-2)

简单的if-else怎么样?

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