迭代器有了__next__为什么还要__iter__

来源:互联网 发布:sql格式化日期 编辑:程序博客网 时间:2024/06/09 21:22

最近看CloseableQueue实现时遇到一个很基础却一直没想的问题。

Python的迭代器中为什么需要实现两个魔法方法?

其实咋一看起作用的不就是__next__方法嘛,__iter__在打酱油?

我知道for in循环是靠__iter__协议机制实现的迭代,但干嘛不直接调next呢?为什么很多迭代器都要return self?

然后找了点相关资料,终于有了点理解。


概念

Python中关于迭代有两个概念,第一个是Iterable,第二个是Iterator,协议规定Iterable的__iter__方法会返回一个Iterator, Iterator的__next__方法(Python 2里是next)会返回下一个迭代对象,如果迭代结束则抛出StopIteration异常。

理解

怎么理解呢?也就是iterator才是被调用next返回下一个迭代对象的类,而iterable是不一定具备这样的能力的,iterable的协议内容是其能返回一个iterator。当然,iterator也必须要实现__iter__方法,返回自己,这是协议上的统一实现。

为什么要这样设计协议呢?

假设我们现在只留下next接口,任何循环迭代情况直接调用next()方法,如果遇到一个结构直接用next实现迭代数据或迭代器生成器都直接暴露的那可以,如果遇到一个用生成器实现迭代数据,而代码被设置在一个结构内部怎么办,我们就必须先通过结构内部的方法将生成器取到外面,然后由生成器逐渐取得外部数据。不然每次直接对这个结构调用next只会得到一堆生成器,这太傻了。

这样的话不如定义一个协议,让所有这种包含生成器情况的结构有一个公共方法__iter__,循环结构直接用这个结构取代真正的iterator,用这个__iter__自动取出内部的生成器再取得数据。这样的代码优雅又方便,这个包含数据的外部结构就是 iterable。这种协议在next实现的迭代器中,就直接返回self,这样就实现了接口的统一。

另外,__iter__接口还可以在返回迭代器之前对迭代器做一些处理,list,dic等数据结构可以重复遍历甚至并发遍历,它们在iter返回的是独立的迭代器,迭代过程互不影响,这也是__iter__这个接口的作用。当然,具体list如何返回独立迭代器代码没看过。也只是看到别人这么提到。在自己的代码中如何应用这个特性暂不清楚。


0 0