7

有几种方法可以打破几个嵌套循环

他们是:

1)使用break-continue

for x in xrange(10):
    for y in xrange(10):
        print x*y
        if x*y > 50:
            break
    else:
        continue  # only executed if break was not used
    break

2)使用返回

def foo():
    for x in range(10):
        for y in range(10):
            print x*y
            if x*y > 50:
                return
foo()

3)使用特殊异常

class BreakIt(Exception): pass

try:
    for x in range(10):
        for y in range(10):
            print x*y
            if x*y > 50:
                raise BreakIt
except BreakIt:
    pass

我有一些想法,可能有其他方法可以做到这一点。它是通过使用 StopIteration 将异常直接发送到外循环。我写了这段代码

it = iter(range(10))
for i in it:
    for j in range(10):
        if i*j == 20:
            raise StopIteration

不幸的是,StopIteration 没有被任何 for 循环捕获,并且该代码产生了丑陋的 Traceback。我认为这是因为 StopIteration 不是从 iterator it内部发送的。(这是我的猜测,我不确定)。

有什么方法可以将 StopIteration 发送到外循环?

谢谢!

4

4 回答 4

4

您希望打破的嵌套循环的另一种方法是折叠它们。所以像

for x, y in ((x, y) for x in range(10) for y in range(10)):
    print x*y
    if x*y > 50: break
于 2011-08-03T00:21:12.123 回答
4

你可以用协程做这样的事情:

def stoppable_iter(iterable):
    it = iter(iterable)
    for v in it:
        x = yield v
        if x:
            yield
            return

然后像这样使用它:

it = stoppable_iter(range(10))
for i in it:
    for j in range(10):
        print i, j
        if i*j == 20:
            it.send(StopIteration) # or any value that evaluates as True
            break

以及它如何工作的一个简短示例:

>>> t = stoppable_iter(range(10))
>>> t.next()
0
>>> t.next()
1
>>> t.send(StopIteration)
>>> t.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
于 2011-08-03T00:33:02.803 回答
1

我认为这是因为StopIteration不是从 iterator 内部发送的it。(这是我的猜测,我不确定)。

非常正确。

有什么方法可以发送StopIteration到另一个循环?

与您的#3 相同,除了使用StopIteration而不是您定义的异常。无论如何,这是一个很好的使用。

在评论中,我提到编写一个迭代器,可以告诉它在下一次循环中引发 StopIteration。这是我正在谈论的事情:

class StoppableIterator(object):
    def __init__(self, iterable):
        self._iter = iter(iterable)
        self._stop = False
    def __iter__(self):
        return self
    def stop(self):
        self._stop = True
    def next(self):
        if self._stop:
            raise StopIteration
        return next(self._iter)

用法:

si = StoppableIterator([2, 3, 5, 7, 11, 13])
for i in si:
    for j in xrange(i):
         print i, j
         if j == 7:
             si.stop()   # will break out of outer loop next iteration
             break       # breaks out of inner loop
于 2011-08-03T00:15:48.943 回答
1

您可以使用.close自 Python 2.5 以来每个生成器都有的 :

代码在 Python 3.2 中,但它也应该在 2.x 中工作。
在 Python 2.x 中,我会使用xrange而不是range.

outer_loop_iterator = (i for i in range(10)) #we need named generator
for x in outer_loop_iterator:
    for y in range(10):
        print(x*y)
        if x*y > 50:
            outer_loop_iterator.close()
            break #I'm affraid that without this inner loop could still work
于 2014-11-23T11:14:35.247 回答