【问题标题】:Using for...else in Python generators在 Python 生成器中使用 for...else
【发布时间】:2010-10-10 20:36:17
【问题描述】:

我是 Python 的 for...else syntax 的忠实粉丝——令人惊讶的是它的适用频率以及它在简化代码方面的效率。

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

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

在上面的示例中,我希望仅当 i 为空时才执行 print 语句。但是,由于else 只尊重breakreturn,所以不管i 的长度如何,它总是会被执行。

如果无法以这种方式使用for...else,那么最好的方法是什么,以便仅在没有任何结果时执行print 语句?

【问题讨论】:

    标签: python syntax for-loop generator yield


    【解决方案1】:

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

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

    【讨论】:

    • return 隐含在生成器的末尾。不需要包含它。
    • 我是这么想的,但我想我会在这里明确说明。
    • +1: "print i is empty" 是别人的问题,不是生成器的问题。
    • 这根本不能回答问题,是吗?问题是如果您正在迭代的对象不包含任何对象,如何在生成器函数中执行一些代码。
    • @Chris B:这个问题反映了一些不是很 Pythonic 的东西。与其用晦涩的代码使问题复杂化,不如提供一个更 Python 的解决方案。
    【解决方案2】:

    有几种方法可以做到这一点。你总是可以直接使用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()
    

    【讨论】:

      【解决方案3】:

      总结之前的一些答案,可以这样解决:

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

      所以确实没有涉及“else”子句。

      【讨论】:

        【解决方案4】:

        如您所述,for..else 仅检测到 break。所以它只适用于你寻找某物然后停止

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

        无论是否生成器,您都需要一个布尔值,就像 Ber 的解决方案一样。

        【讨论】:

          【解决方案5】:

          如果无法以这种方式使用 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 >>>

          【讨论】:

            【解决方案6】:

            简单的 if-else 怎么样?

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

            【讨论】:

            • 参数 i 可能没有定义 len,所以这是有问题的。
            • 与递归的答案相同的问题,或多或少。
            猜你喜欢
            • 1970-01-01
            • 2016-01-08
            • 2012-08-20
            • 2021-03-19
            • 1970-01-01
            • 1970-01-01
            • 2018-04-14
            • 2015-06-16
            相关资源
            最近更新 更多