为什么 Python 迭代器需要 dunder iter 函数?

pax*_*blo 1 iterator python-3.x

根据文档,需要可迭代的容器应该提供一个__iter__()返回迭代器的函数。迭代器本身需要遵循迭代器协议,这意味着它必须提供__iter__()返回自身,并__next__()提供下一个项目,或者引发一个StopIterator异常的功能。

现在我明白为什么在执行自己的迭代的容器中需要这两者,因为您必须提供迭代器和下一项:

class ObjAndIter:
    def __init__(self):
        pass
    def __iter__(self):
        return self
    def __next__(self):
        # return something intelligent or raise StopIterator

for i in ObjAndIter():
    pass
Run Code Online (Sandbox Code Playgroud)

但是,在迭代器是不同类型的情况下,我看不到迭代迭代器本身的用例。考虑一个(人为的)类,它什么也不做,只是提供一个迭代器来从给定数字向上计数到某个限制:

class MyObj:
    class MyIter:
        def __init__(self, start, end):
            self._num = start - 1
            self._end = end

        def __next__(self):
            self._num += 1
            if self._num > self._end:
                raise StopIteration
            return self._num

        #def __iter__(self): # This is apparently required but
        #    return self     #   it runs fine without it.

    def __init__(self, start, end):
        self._start = start
        self._end = end

    def __iter__(self):
        return self.MyIter(self._start, self._end)

x = MyObj(5, 10)
for i in x:
    print(i)
Run Code Online (Sandbox Code Playgroud)

现在这似乎适用于以下情况:

x = MyObj(5, 10)
for i in x:
    print(i)
Run Code Online (Sandbox Code Playgroud)

尽管事实上迭代器不遵循迭代器协议 - 它提供了__next__()但不是__iter__()。该__iter__()函数仅在容器上调用,并且__next__()仅在迭代器上调用。

现在如果没有迭代器 __iter__()函数,我发现您将无法执行以下操作:

x = MyObj(5, 10)
xiter = x.__iter__()
for i in xiter:
    print(i)
Run Code Online (Sandbox Code Playgroud)

但我很难想象何时需要在迭代器(而不是容器)上创建迭代器。

所以我的问题是这样的。什么情况下我需要这样做?如果没有这个,拥有迭代器协议似乎就没有什么意义了,除非容器必须提供__iter__()并且迭代器必须提供__next__()


顺便说一句,我已经看到了这个问题及其答案,但它们似乎没有涵盖为什么迭代器需要可迭代。我可以很清楚地看到,它使代码更容易迭代容器迭代器,但这个问题是关于为什么后者是必要的。

Jul*_*ard 5

迭代器需要可迭代才能支持 for 循环和 iter()。

这导致:为什么要迭代迭代器?

因为有时你会直接得到迭代器,例如打开的文件或生成器函数:

>>> def gen():
...     yield 1
...     yield 2
...
>>> it = gen()
>>> hasattr(it, '__next__')
True
Run Code Online (Sandbox Code Playgroud)

这导致:为什么Python的某些部分返回一个interator而不是一个iterable?

这是一种告诉事物“不可倒带”/“一次性可迭代”的方法。因为返回一个可迭代对象会说“你可以对其调用两次 iter() 来迭代它两次”,这是错误的。

  • 在重新阅读这个答案时,我实际上对其中的区别印象深刻,而我最初并没有完全理解这一点。迭代器(一次性)是您可以迭代的东西,仅此而已。可迭代对象可以为您提供任意次数的迭代器。如果可以的话我会再次投票:-) (2认同)