自定义iterator和itertools.tee问题

时间:2019-05-09 13:04:48

标签: python iterator itertools

我的自定义迭代器应在调用next时调用特定方法。最初,它的工作方式是这样,但是在第二次在迭代器上调用itertools.tee之后,该方法没有被调用。

我实际上已经有解决方案/解决方法,但是我想了解问题的根本原因。

class MyIterator(object):
    def __init__(self, elements):
        self._elements = iter(elements)

    def __iter__(self):
        return self

    def next(self):
        element = (self._elements)

        if isinstance(element, HwState):
            element.el_method()

        return element

elements = list(...)
iterator1, iterator2 = itertools.tee(MyIterator(elements))
element1 = next(iterator2)    # ok
element2 = next(iterator2)    # ok
iterator1, iterator2 = itertools.tee(MyIterator(iterator1))
element1 = next(iterator2)    # el_method() is not called but correct element is returned
element2 = next(iterator2)    # el_method() is not called but correct element is returned

我通过这种方式“解决”了这个问题:

elements = list(...)
iterator = MyIterator(elements)
element1 = next(iterator)
element2 = next(iterator)
iterator = MyIterator(elements)
element1 = next(iterator)    # el_method() is called, correct element is returned
element2 = next(iterator)    # el_method() is called, correct element is returned

1 个答案:

答案 0 :(得分:0)

请参阅文档中包含的itertools.tee的“大致等效”实现:

def tee(iterable, n=2):
    it = iter(iterable)
    deques = [collections.deque() for i in range(n)]
    def gen(mydeque):
        while True:
            if not mydeque:             # when the local deque is empty
                try:
                    newval = next(it)   # fetch a new value and
                except StopIteration:
                    return
                for d in deques:        # load it to all the deques
                    d.append(newval)
            yield mydeque.popleft()
    return tuple(gen(d) for d in deques)

本质上,tee为每个生成的迭代器保留一个队列。当请求一个新值时,如果迭代器队列中有内容,它将从那里获取下一个值;如果队列为空,它将在原始迭代器上调用next一次,并将结果添加到每个队列中。这意味着生成的值被“缓存”并由每个迭代器返回,而不是重复生成元素的工作。

此外,tee通常不可能像您期望的那样运行,因为tee通常不知道如何制作迭代器的副本。例如考虑一个文本文件。一旦您原则上阅读了一行,就无法返回(在简单的顺序访问中),也就没有这样的“复制文件迭代器”之类的东西(要模拟这样的事情,您将需要多个文件处理程序或查找),因此您只需保存所读取的行,然后在其他迭代器中将其返回。