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

发布于 2024-07-14 08:19:51 字数 604 浏览 11 评论 0原文

我非常喜欢 Python 的 for...else 语法 - 令人惊讶的是它的适用频率以及它如何有效地简化代码。

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

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

在上面的示例中,我希望仅在 i< 时才执行 print 语句/代码> 为空。 然而,由于 else 只考虑 breakreturn,因此无论 i 的长度如何,它总是会被执行。

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

I'm a big fan of Python's for...else syntax - it's surprising how often it's applicable, and how effectively it can simplify code.

However, I've not figured out a nice way to use it in a generator, for example:

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

In the above example, I'd like the print statement to be executed only if i is empty. However, as else only respects break and return, it is always executed, regardless of the length of i.

If it's impossible to use for...else in this way, what's the best approach to this so that the print statement is only executed when nothing is yielded?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

避讳 2024-07-21 08:19:52

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

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

You're breaking the definition of a generator, which should throw a StopIteration exception when iteration is complete (which is automatically handled by a return statement in a generator function)

So:

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

Best to let the calling code handle the case of an empty iterator:

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

Might be a cleaner way of doing the above, but that ought to work fine, and doesn't fall into any of the common 'treating an iterator like a list' traps below.

千纸鹤带着心事 2024-07-21 08:19:52

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

There are a couple ways of doing this. You could always use the Iterator directly:

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

But if you know more about what to expect from the argument i, you can be more concise:

def iterate(i):
    if i:  # or if len(i) == 0
        for next in i:
            yield next
    else:
        print 'i is empty'
        raise StopIteration()
作妖 2024-07-21 08:19:52

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

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

    if empty:
        print "empty"

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

Summing up some of the earlier answers, it could be solved like this:

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

    if empty:
        print "empty"

so there really is no "else" clause involved.

终遇你 2024-07-21 08:19:52

正如您所注意到的,for..else 仅检测break。 因此,它仅适用于当您寻找某物然后停止时。

它不适用于您的目的,不是因为它是一个生成器,而是因为您想不间断地处理所有元素(因为您想生成所有元素,但这不是重点)。

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

As you note, for..else only detects a break. So it's only applicable when you look for something and then stop.

It's not applicable to your purpose not because it's a generator, but because you want to process all elements, without stopping (because you want to yield them all, but that's not the point).

So generator or not, you really need a boolean, as in Ber's solution.

昨迟人 2024-07-21 08:19:52

<块引用>

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

If it's impossible to use for...else in this way, what's the best approach to this so that the print statement is only executed when nothing is yielded?

Maximum i can think of:


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

仅冇旳回忆 2024-07-21 08:19:52

简单的 if-else 怎么样?

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

What about simple if-else?

def iterate(i):
    if len(i) == 0: print 'i is empty'
    else:
        for value in i:
            yield value
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文