如何优雅地使用Python迭代器

时间:2010-12-10 09:05:06

标签: python loops iterator

我试图更多地使用迭代器进行循环,因为我听说它比索引循环更快。我不确定的一件事是如何很好地对待序列的结束。我能想到的方法是使用tryexcept StopIteration,这看起来很难看。

更具体地说,假设我们要求打印两个排序列表ab的合并排序列表。我会写下面的

aNull = False
I = iter(a)
try:
    tmp = I.next()
except StopIteration:
    aNull = True

for x in b:
    if aNull:
        print x
    else:
        if x < tmp:
            print x
        else:
            print tmp,x
            try:
                tmp = I.next()
            except StopIteration:
                aNull = True

while not aNull:
    print tmp
    try:
        tmp = I.next()
    except StopIteration:
        aNull = True

你会如何编码以使其更整洁?

3 个答案:

答案 0 :(得分:8)

我认为更加对称地处理ab会使其更容易阅读。此外,使用Python 2.6中的内置next函数使用默认值可以避免处理StopIteration的需要:

def merge(a, b):
    """Merges two iterators a and b, returning a single iterator that yields
    the elements of a and b in non-decreasing order.  a and b are assumed to each
    yield their elements in non-decreasing order."""

    done = object()
    aNext = next(a, done)
    bNext = next(b, done)

    while (aNext is not done) or (bNext is not done):
        if (bNext is done) or ((aNext is not done) and (aNext < bNext)):
            yield aNext
            aNext = next(a, done)
        else:
            yield bNext
            bNext = next(b, done)

for i in merge(iter(a), iter(b)):
    print i

以下函数概括了为任意多个迭代器工作的方法。

def merge(*iterators):
    """Merges a collection of iterators, returning a single iterator that yields
    the elements of the original iterators in non-decreasing order.  Each of
    the original iterators is assumed to yield its elements in non-decreasing
    order."""

    done = object()
    n = [next(it, done) for it in iterators]

    while any(v is not done for v in n):
        v, i = min((v, i) for (i, v) in enumerate(n) if v is not done)
        yield v
        n[i] = next(iterators[i], done)

答案 1 :(得分:6)

你错过了迭代器的全部内容。您不需要手动调用I.next(),只需遍历I

for tmp in I:
    print tmp

<强>被修改

要合并两个迭代器,请使用itertools模块中非常方便的函数。你想要的可能是izip

merged = []
for x, y in itertools.izip(a, b):
    if x < y:
        merged.append(x)
        merged.append(y)
    else:
        merged.append(y)
        merged.append(x)

再次修改

正如评论中所指出的,这实际上不起作用,因为列表中的多个项目可能比列表b中的下一个项目小。但是,我意识到还有另一个内置函数可以解决这个问题:heapq.merge

答案 2 :(得分:0)

函数 sorted 适用于列表和迭代器。也许这不是你想要的,但下面的代码可以工作。


a.expand(b)
print sorted(iter(a))