7

如果迭代完成但没有被 中断,则/子句中的else块将被执行,因此我阅读了.forelsebreak

有没有一种语言结构可以让我写一些只有在for循环没有开始迭代时才执行的东西?如果我使用tupleor list,我会做这样的事情:

if seq:
    for x in seq:
         # something
else:
    # something else

但是当我使用生成器时,我没有得到我想要的行为:

>>> g = (x for x in range(2))
>>> for x in g:
...     print x
... else:
...     print "done"
... 
0
1
done    # I don't want "done" here
>>> g = (x for x in range(2) if x > 1)
>>> if g:
...     for x in g:
...         print x
... else:
...     print "done"
... 
>>>     # I was expecting "done" here

我怎样才能做到这一点,而不用从生成器创建 atuple或 a list,同时还使用for循环?我可以next()while循环中使用并尝试捕捉StopIteration,但我想看看是否有一个很好的方法来做到这一点for

4

7 回答 7

6
n = -1
for n, i in enumerate(it):
    do_stuff()
if n < 0:
    print 'Done'
于 2013-08-07T19:40:04.970 回答
5

我想不出比在 for 循环中更新布尔值更好的方法。

any_results = False
for x in g:
    any_results = True
    print x
if not any_results:
    print 'Done'
于 2013-08-07T19:35:17.843 回答
5

我发现这个解决方案好多了。查看这个链接了解更多信息(http://python-notes.curiousefficiency.org/en/latest/python_concepts/break_else.html)。

您可以使用自定义标记:x = no_data = object()

x = no_data = object()
for x in data:
    .......
if x is no_data:
    print "Loop did not run"

object() 返回一个无特征的对象,它是所有类的基础。

is 检查两个对象是否相同(x 是 no_data)。如果它们保持相同,则表示控件从未进入 for 循环。

于 2017-03-22T06:08:20.300 回答
2

您可以使用生成器功能:

next接受可选的第二个参数,可用于在迭代器耗尽时指定默认值。

def func(lis):
    g = (x for x in lis if x > 1)
    flag = object()      # expected to be unique
    nex = next(g, flag)  # will return flag if genexp is empty
    if nex is not flag:
        yield nex
        for item in g:
            yield item
    else:
        yield "done"

for x in func(range(2)):
    print x
print "------"
for x in func(range(4)):
    print x

输出:

done
------
2
3
于 2013-08-07T19:38:29.353 回答
0

我认为了解循环是否实际执行的一个好方法是使用循环变量

lv= 1
for x in g:
    lv = lv+1
    print x
if (lv == 1):
    print 'Done'

我的语法可能是错误的,因为我不是 python 人..

于 2013-08-07T19:38:21.127 回答
0

您可以编写一个计算迭代次数的包装器。它的优点是可以处理更多奇特的枚举。在 python3 中,它会是这样的:

import sys
from glob import iglob

class GenCount(object):

    def __init__(self, gen):
        self._iter = iter(gen)
        self.count = 0

    def __next__(self):
        val = self._iter.__next__()
        self.count += 1
        return val

    def __iter__(self):
       return self

c = GenCount(iglob(sys.argv[1]))
for fn in c:
    print(fn)
print(c.count)


c = GenCount(iglob(sys.argv[1]))
print([fn for fn in c])
print(c.count)
于 2013-08-07T20:10:37.620 回答
-1

在这里的例子中,你需要一个额外的构造吗?

caught = None
for item in x:
    caught = item
    print caught
if caught != None: print "done"

*为 OP 评论编辑*t

于 2013-08-07T19:40:29.740 回答