【问题标题】:Custom iterator and itertools.tee problem自定义迭代器和 itertools.tee 问题
【发布时间】:2019-05-09 13:04:48
【问题描述】:

我的自定义迭代器应该在调用 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

【问题讨论】:

    标签: python iterator itertools


    【解决方案1】:

    请参阅文档中包含的 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 通常不知道如何复制迭代器。例如考虑一个文本文件。一旦您原则上阅读了一行,您就不能返回(在简单的顺序访问中),并且没有“复制文件迭代器”之类的东西(要模拟类似的东西,您需要多个文件处理程序或查找),所以您只需保存您读取的行并稍后在其他迭代器中返回它们。

    【讨论】:

    • 我仍然需要在调试器中运行代码才能理解它,但现在我知道它为什么会这样了。谢谢!虽然我不明白为什么 tee 不知道如何复制迭代器。我对 C++ 更熟悉,在这种情况下,next 的地址将被复制到新对象中,这很容易
    • @ArturStępniak 问题在于,在 Python 中,迭代器可以是许多不同的东西。例如,网络流可以作为迭代器读取,但不能复制(您可以缓冲已读取的内容,就像tee 所做的那样,但您不能“重新读取”​​数据)。同样,生成器函数生成没有复制方法的迭代器(迭代器本质上包含一个调用堆栈)。我认为原则上可以复制集合迭代器,但“始终有效”的唯一方法是缓存。希望对一些人有所帮助。
    • 我现在明白了。谢谢
    猜你喜欢
    • 2020-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-05
    • 2015-02-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多