只有当for循环没有开始迭代(使用生成器)时,Python才会执行代码?

时间:2013-08-07 19:23:52

标签: python python-2.7 generator

如果迭代结束但elseso I read没有中断,for / else子句中的break块将被执行。

是否有一种语言结构可以让我编写只在for循环没有开始迭代时执行的内容?如果我使用的是tuplelist,我会这样做:

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

如何在不浪费的情况下从生成器创建tuplelist,同时还使用for循环?我可以在next()循环中使用while并尝试捕获StopIteration,但我想看看是否有一种很好的方法可以使用for

7 个答案:

答案 0 :(得分:4)

n = -1
for n, i in enumerate(it):
    do_stuff()
if n < 0:
    print 'Done'

答案 1 :(得分:3)

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

any_results = False
for x in g:
    any_results = True
    print x
if not any_results:
    print 'Done'

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

答案 3 :(得分:1)

我发现此解决方案要好得多。请查看此链接以获取更多信息(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()返回一个无特征的对象,它是所有类的基础。

检查两个对象是否相同(x是no_data)。如果它们保持不变,则意味着控件永远不会进入for循环。

答案 4 :(得分:0)

我认为通过使用循环变量

来了解循环实际执行情况的好方法
lv= 1
for x in g:
    lv = lv+1
    print x
if (lv == 1):
    print 'Done'

我的语法可能有误,因为我不是蟒蛇人......

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

答案 6 :(得分:-1)

在这里的示例中,您是否需要额外的构造?

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

*编辑OP commen * t