为什么Python迭代器需要dunder迭代器功能? [英] Why does a Python iterator need a dunder iter function?

查看:79
本文介绍了为什么Python迭代器需要dunder迭代器功能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据文档,该容器需要iterable应该提供一个 __ iter __()函数以返回迭代器.迭代器本身必须遵循迭代器协议,这意味着它必须提供返回自身的 __ iter __()和提供下一项或引发的 __ next __() StopIterator 异常.

现在,我理解为什么在进行其自己迭代的容器中都需要同时使用这两种方法,因为您必须同时提供迭代器和下一项:

  ObjAndIter类:def __init __():经过def __iter __(自己):回归自我def __next __(self):#返回一些聪明的东西或提高StopIterator对于我在ObjAndIter()中:经过 

但是,在迭代器是不同类型的情况下,我看不到在迭代器本身上进行迭代的用例.考虑一个(伪造的)类,该类什么都不做,只提供一个迭代器,以从给定的数字向上计数到某个限制:

  MyObj类:MyIter类:def __init __(自身,开始,结束):self._num =开始-1self._end =结束def __next __(self):self._num + = 1如果self._num>自我_结束:提高StopIteration返回self._num#def __iter __(self):#这显然是必需的,但#return self#没有它就可以正常运行.def __init __(自身,开始,结束):self._start =开始self._end =结束def __iter __(自己):返回self.MyIter(self._start,self._end)x = MyObj(5,10)对于x中的我:打印(i) 

现在,这似乎可以与类似的东西配合使用

  x = MyObj(5,10)对于x中的我:打印(i) 

尽管是迭代器不遵循迭代器协议的事实-它提供了 __ next __(),但没有提供 __ iter __().仅在容器上调用 __ iter __()函数,而仅在迭代器上调用 __ next __().

现在没有 iterator __ iter __()函数,我发现您将无法执行以下操作:

  x = MyObj(5,10)xiter = x .__ iter __()对于我而言:打印(i) 

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

所以我的问题是这个.在什么情况下我需要这样做?否则,根本没有迭代器协议的意义,除了可能容器必须提供 __ iter __()和迭代器必须提供 __ next __().


顺便说一句,我已经看到了解决方案

迭代器需要可迭代以支持for循环和iter().

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

因为有时会直接给您迭代器,例如Calendar.iterweekdays 或生成器函数的迭代器:

 >>>def gen():...产量1...产量2...>>>它= gen()>>>hasattr(it,'__next__')真的 

这导致:为什么Python的某些部分返回Interator而不是可迭代的?

这是一种告诉事物不可倒带"的方式./一次性可迭代".如返回可迭代对象会说您可以在其上调用iter()两次以对其进行迭代两次",这是错误的.

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.

解决方案

Iterators needs to be iterable to support for-loops and iter().

This lead to: Why one would want to iterate over an iterator?

Because sometimes you're directly given iterators, for example Calendar.iterweekdays or a generator function an iterator:

>>> def gen():
...     yield 1
...     yield 2
...
>>> it = gen()
>>> hasattr(it, '__next__')
True

This lead to: Why some parts of Python returns an interator instead of an iterable?

This is a way to tell the thing is "not rewindable" / "one-shot iterable". As returning an iterable would say "You can call iter() twice on it to iterate twice over it", which would be wrong.

这篇关于为什么Python迭代器需要dunder迭代器功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆