Python 迭代器(iterator)与生成器(generator)

一、概念


    容器(container):容器是一种把多个元素组织在一起的数据结构,将大部分数据保存在内存中

    可迭代对象(Iterable):通俗的说就是在数据类型对象中,只要包含__iter__()

    迭代器(Iterator):通俗来讲任何具有__next__()方法的对象都是迭代器

    生成器(generator):使用了 yield 的函数被称为生成器(generator)。是一种特殊的、一种更为高级的、更为优雅的迭代器。返回可以迭代对象的函数


二、容器( Container)

    容器中的元素可以逐个地迭代获取,可以用in, not in关键字判断元素是否包含在容器中。通常这类数据结构把大部分的元素存储在内存中(也有一些特例,并不是所有的元素都放在内存,比如迭代器和生成器对象),在Python中,常见的容器对象有:

    list, deque, ….

    set, frozensets, ….

    dict, defaultdict, OrderedDict, Counter, ….

    tuple, namedtuple, …

    str

    容器相对来说很好理解,因为你可以把它当成生活中的箱子、房子、船等等里面可以塞任何东西。从技术角度来说,当通过判断一个对象是否包含某个元素来确定它是否为一个容器 

容器示例

    尽管绝大多数容器都提供了某种方式来获取其中的每一个元素,但这并不是容器本身提供的能力,而是可迭代对象赋予了容器这种能力,当然并不是所有的容器都是可迭代的,比如:Bloom filter,虽然Bloom filter可以用来检测某个元素是否包含在容器中,但是并不能从容器中获取其中的每一个值,因为Bloom filter压根就没把元素存储在容器中,而是通过一个散列函数映射成一个值保存在数组中。参考:Python3 迭代器和生成器 - 迷鸟归林 - 博客园


三、迭代器(Iterator)

    迭代器是 Python 最强大的功能之一,是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。迭代器有两个基本的方法:iter() 和 next()

    字符串,列表或元组对象都可用于创建迭代器,以下示例:

    迭代器调用__next__()方法可以获取下一个值, 实际调用过程如下:

引用过程图

    那么如何判断一个对象是否是可迭代呢?可迭代对象可以为任意对象,不一定非得是基本数据结构,只要这个对象可以返回一个iterator, 可以使用 collections 模块的 Iterable 类型判断:

    把一个类作为一个迭代器使用需要在类中实现两个方法 __iter__()与__next__() 。如果你已经了解的面向对象编程,就知道类都有一个构造函数,Python的构造函数为__init__(), 它会在对象初始化的时候执行。__iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了__next__() 方法并通过StopIteration异常标识迭代的完成。

    下面我们来创建一个迭代器:

    StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 __next__() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。

    可迭代对象: 本质是提供一个中间人,遍历的时候, 需要数据的时候, 获取这个对象的迭代器, 然后通过迭代器依次获取对象中的数据。具备了一个__iter__ 方法的对象就是一个可迭代对象。通过iter方法获得可迭代对象的迭代器, 然后对迭代器使用next() 方法, 获取下一个数据。

迭代器的作用:
    迭代器最核心的功能是通过next()函数的调用来返回下一个数据值。如果每次返回的数据值不是在一个已有的数据集合中读取的,而是通过程序按照一定的规律计算生成的 * 可以节省内存和存储空间。如果我们产生的数据很多, 数据量很大的话,很容易把进程跑死或者把服务器跑崩溃。


四、生成器(Generator)

    在Python中,使用了 yield 的函数被称为生成器(generator)。跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。调用一个生成器函数,返回的是一个迭代器对象。

    生成器是一种特殊的迭代器, 保存当前运行的状态。在Python中有两种类型的生成器:生成器表达式以及生成器函数。生成器函数就是包含 yield 参数的函数。生成器表达式与列表解析式类似。

先看第一种生成器表达式:

第一种方法很简单,只要把一个列表生成式的 [ ] 改成 ( )
L = [x*2 for x in range(5)]
print(L)
# 输出:[0, 2, 4, 6, 8]
G = (x*2 for x in range(5))
print(G)
# 输出:<generator object <genexpr> at 0x000001CDCF78B8C8>

print("length L:", type(L))  # 输出列表的长度 10
print("length G:", len(G))  # TypeError: object of type 'generator' has no len(),因为生成器不能直接给出长度!!!
# 注意点:二者输出等价,不过 G 是在运行时开辟内存,而 L 是直接开辟内存


第二种生成器函数:

    第二种方法使用 yeild 函数 ,在函数( __ next __)中使用 yeild 关键字,属于生成器函数。在一般函数中使用 yield 关键字,可以实现一个最简单的生成器,此时这个函数变成一个生成器函数。yield  return 返回相同的值,区别在于return返回后,函数状态终止,而yield会保存当前函数的执行状态,在返回后,函数又回到之前保存的状态继续执行。

    声明:1.任意生成器都是迭代器(反过来不成立)2.任意生成器,都是一个可以延迟创建值的工厂

    以下实例使用 yield 实现斐波那契数列:

那么生成器函数与一般函数的区别:

1.生成器函数包含一个或者多个yield
2.调用生成器函数时,函数将返回一个对象,延迟暂停向下执行
3.__iter__()和__next__()方法等是自动实现,通过next()方法进行迭代对象
4.一旦函数 使用关键字 yield,函数会暂停,控制权返回调用者,局部变量和它们的状态会被保存,直到下一次调用
5.函数终止的时候,StopIteraion会被自动抛出 

总之,生成器是Python中一种非常强大的特性,它让我们能够编写更加简洁的代码,同时也更加节省内存,使用CPU也更加高效。

                                                                    --大多数人想要改造这个世界,但却罕有人想改造自己--

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

推荐阅读更多精彩内容