Why does a Python iterator need a dunder iter function?

﹥>﹥吖頭↗ 提交于 2021-02-11 14:21:33

问题


According to the documentation, a container that needs to be iterable should supply an __iter__() function to return an iterator. The iterator itself is required to follow the iterator protocol, meaning that it has to provide __iter__() that returns itself, and __next__() that provides the next item, or raises a StopIterator exception.

Now I understand why both of those would be required in a container that does its own iteration, since you have to both provide an iterator and a next item:

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

However, in the case where the iterator is a different type, I can't see the use case for iterating over the iterator itself. Consider a (contrived) class that does nothing but provide an iterator to count up from a given number to some limit:

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)

Now this appears to work fine with things like:

x = MyObj(5, 10)
for i in x:
    print(i)

despite the fact that the iterator doesn't follow the iterator protocol - it provides __next__() but not __iter__(). The __iter__() function is only called on the container and __next__() is only called on the iterator.

Now without the iterator __iter__() function, I see that you wouldn't be able to do something like:

x = MyObj(5, 10)
xiter = x.__iter__()
for i in xiter:
    print(i)

but I'm having a hard time envisaging when I would ever need to create an iterator over an iterator (rather than over a container).

So my question is this. Under what circumstances would I need to do this? Without that, there seems little point in having an iterator protocol at all, except possibly that the container must provide __iter__() and the iterator must provide __next__().


As an aside, I have seen this question, and its answers, but they seem to not cover why an iterator needs to be iterable. I can see quite well that it makes it easier for code to iterate over both the container and the iterator but this question is about why the latter is even necessary.

来源:https://stackoverflow.com/questions/64204931/why-does-a-python-iterator-need-a-dunder-iter-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!