Python Iterable vs Iterator vs Generator

提前声明:本文学习笔记
原文英文内容为:http://nvie.com/posts/iterators-vs-generators/

Containers 容器

容器是一个装在元素的数据结构,他支持各种测试。这些数据结构活动于内存中,大多数情况下数据也会存储在内存中。
在 Python 中,有一些熟知的例子:

  • list
  • set
  • dict
  • tuple
  • str
    这些数据结构都有自己的子集,具体就不在这里过过多的叙述。

Containers 很容易掌握,因为你可以完全把它们当作现实生活中的容器,比如一个盒子,一座房子,或者一艘船等等

严格意义上来说,如果一个对象可以是否能容下真实的元素,那么他就可以被称为容器。可以以lists,sets,tuples 作为测试的执行对象。

Iterables 可迭代对象

简单的说,大部分容器都是可迭代对象。
但是还有很多内容也是可迭代的,比如说打开文件,连接套接字等等。
Container 大多是有限的,但是可迭代对象或许代表了无限的数据源。

iterable 是一个对象,而不仅仅是一个数据结构,他可以返回一个迭代器(用于返回所有的元素)。这样表述有点疑惑,但是iterable和iterator有着非常重要的区别。

提示:
通常来说,出于务实的原因,iterable 类在类中实现两个方法: iter() 和 next(),并且返回 iter() 给 self,这使得大多数的 iterable 类既是 itreable 也有 迭代器iterator。

Iterator 迭代器

所以,那什么才是迭代器 iterator 呢。
只要能通过调用 next() 提取下一个值就是可以,任何一个对象,如果包含了 next() 方法,那么它就是一个迭代器。至于如何获取下一个值无关紧要,这一点就保障了它是一个迭代器。

迭代器可以理解为 取值的工厂类,每次需要取值只需要调用 the next 即可,它知道如何计算因为iterator控制者内部状态。

迭代器的例子非常多,所有的 itertools 中的方法返回的都是迭代器,有些迭代器会产生无限的序列,有些产生有限长度的序列。

Generator 生成器

最后一个,生成器,generator 是一个特殊的迭代器——更优雅的迭代器

生成器也可以编写一个迭代器类似于 斐波那契数列,它以一种优雅且简易的语法来避免在类中写 iter() 和 next() 方法。

def fib():
    prev, curr = 0, 1
    while True:
        yield curr
        prev, curr = curr, prev + curr
f = fib()
list(islice(f, 0, 10))

>>> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

是不是很优雅,注意到一个非常有魔力的关键字没,它对于美化代码起了关键性的作用

yield

让我们层层分析其中的奥秘:
首先,记住 fib 方法只是一个普通的 Python 方法,没什么特殊性。
但是值得注意的是,在整个方法体中并没有 return (返回)任何关键字。这个方法返回的值被作为generator(一个iterator,一个工厂类,控制状态的对象)

然后,当 f = fib() 被调用,生成器 generator(一个工厂)会被实例化并且返回。此时不会有任何代码被执行:因为generator是一个懒加载类型的初始化状态。更有趣的是,在 prev, curr = 0, 1 这一行,代码仍然没有被执行。

接下来,generator 实例被 islice() 方法封装,这个方法也是一个 iterator,采用的也是懒加载初始化方法。同样,这里也什么都没有发生。

同样的,迭代器 iterator 被list() 方法包裹,此时回消费所有的参数并且构建一个list。为了这样做,代码才考试调用 islice()实例 中的 next() 方法,再进一步开始调用 f 实例中的 next() 方法。

但是每一次只能执行一步,在第一次调用的时候,代码回执行 prev, curr = 0, 1,然后进入 while Ture循环,然后遇到了 yield curr 语句,它将会生成一个值,与当前 curr 的内容相同,并且再次进入睡眠状态。

此时 generator 生成的值回传送到 islice() 的保重中,它同样会生成一个value (因为现在还没有传送满10个值),接下来list就可以添加 value 1 到list中。

接下来,代码会请求 islice() 获取下一个值,递进请求 f 下一个值,此时会将f从上一个状态‘取消暂停’(唤醒了f实例) ,继续执行下一条语句prev, curr = curr, prev + curr。然后会重新下一个迭代进入 while 循环,继续击中 yield curr语句,返回下一个 curr 值。

以上的步骤将一直发生直到输出了10个元素给list,这时候 list() 会请求 islice() 获取第11个值,islice() 会抛出 StopIteration 异常,表明获取的元素应到底了,list会返回最终的结果:十个元素组成的list,前十个 Fibonacci 数字。
这里提示一下,generator 并没有接受到第十一个 next() 调用,实际上,它再也不会被使用了,稍后会被垃圾回收器处理。

生成器的类型

在Python中有两种类型的生成器 generator:generator functions 和 generator expressions。

generator function 是指任何一个包含 yield 关键字的方法,上面一个例子属于此类。

另一种类型的生成器是一个list语法,类似于generator,它的语法十分优雅,而且使用极少的代码来实现。

numbers = [1, 2, 3, 4, 5, 6]
[x * x for x in numbers]
{x: x * x for x in numbers}
lazy_squares = (x * x for x in numbers)
print(next(lazy_squares))
print(next(lazy_squares))
print(next(lazy_squares))
list(lazy_squares)

总结

generators 是一个实用性非常强的编程结构,它允许你用更少的中间过程来快速编码,另外,它能高效地利用CPU 和内存。它趋向于让你使用更少行的代码。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容