前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >理解Python 生成器与迭代器

理解Python 生成器与迭代器

作者头像
用户1278550
发布2018-08-09 14:38:46
5130
发布2018-08-09 14:38:46
举报
文章被收录于专栏:idbaidba

前言

前一段时间和同事聊到Python技术知识,发现自己对生成器,迭代器傻傻分不清楚,于是乎查文档,找资料,有了此文。

通过本文大家可以了解到迭代器,生成器,生成器表达式,容器的定义以及关系。

一图胜千言

关系图(http://nvie.com/posts/iterators-vs-generators/)

先对上面的关系进行解释说明

生成器包括生成器表达(generator expression)和生成器函数(generator function)。 生成器(generator)是迭代器(iterator),但是反过来不一定成立,同时生成器也是可迭代的。 迭代器(iterator)都是可迭代的(iterable),并且实现了next()/__next()__方法。 元组,列表,集合构成容器这些对象都是可迭代的。

接下来我们深入浅出的去了解迭代器,生成器是什么,如何使用。

可迭代对象

相信大家都知道迭代的含义,就是可以循环遍历。 那什么是可迭代对象?通俗的将就是可以使用for x in iterable_obj 或者while 循环遍历的对象,比如list,set,tuple,dict等对象。我们可以通过isinstance()方法来判断,参考例子:

代码语言:javascript
复制
In [30]: from collections import Iterable
In [31]: isinstance('python', Iterable)
Out[31]: True
In [32]: s=3           # s为数字,不可迭代
In [33]: isinstance(s, Iterable)
Out[33]: False
In [35]: l = [1,2,3,4] #列表可用for循环遍历,可迭代
In [35]: isinstance(l, Iterable)
Out[35]: True
In [37]: w=(1,2,3)     #元组可用for循环遍历,可迭代
In [38]: isinstance(w, Iterable)
Out[38]: True

从上面的检测来看 s=3 ,s是一个数值,不可迭代。其他的对象都是可以被循环访问的,即可迭代。

迭代器

迭代器是可以被next()函数调用并返回下一个值的对象,即Iterator。一个对象可迭代,是否就说明它是迭代器呢?我们继续使用isinstance 检测

代码语言:javascript
复制
In [37]: s=[1,2,3]      #列表可以用for循环遍历,可迭代
In [39]: from collections import Iterable,Iterator
In [40]: isinstance(s, Iterator)
Out[40]: False ##

从结果来看s是一个列表,可迭代的对象(iterable)不一定是迭代器(iterator)。为什么列表,集合,字典等对象是可迭代但是不是迭代器呢?

Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。 我们可以把iterator当做有序序列,但我们不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,只有在需要返回下一个数据时它才会计算,即(lazy evaluation)。构造有几百万个值的列表所占用的内存大于几十M,而迭代器对象占用几十个字节的空间。

如何构造迭代器呢?本文介绍两种方式:

  1. 为容器对象添加 __iter__() 和 __next__() 方法(Python 2.7 中是 next());__iter__() 返回迭代器对象本身 self,__next__() 则返回每次调用 next() 或迭代时的元素; class MyIterator(object): def __init__(self, max): self.max = max # 上边界 self.now = 0 # 当前迭代值,初始为0 def __iter__(self): return self # 返回迭代器本身 def next(self): # 迭代器类必须实现的方法next() while self.now < self.max: self.now += 1 return self.now - 1 #返回当前迭代值 raise StopIteration #超出上边界,抛出异常 In [51]: my=MyIterator(10) In [52]: isinstance(my,Iterable) Out[52]: True In [53]: isinstance(my,Iterator) Out[53]: True
  2. python内置函数 iter() 将可迭代对象转化为迭代器。 l 是一个列表,通过iter() 函数将列表对象转化为迭代器。 In [45]: isinstance(l, Iterator) Out[45]: False In [46]: isinstance(iter(l), Iterator) Out[46]: True

生成器

  生成器是迭代器的一种,不过生成器不需要实现__iter__()和__next__(),只要使用yield关键字返回值。当一个生成器函数调用yield,生成器函数的"状态"会被冻结,所有的变量的值会被保留下来,下一行要执行的代码的位置也会被记录,直到再次调用next()。一旦next()再次被调用,生成器函数会从它上次离开的地方开始。如果永远不调用next(),yield保存的状态就被无视了。从下面的例子可以出来yield运行机制:

代码语言:javascript
复制
 In [79]: def gen():
    ...:     yield 1
    ...:     yield 2
    ...:     yield 3
    ...:

In [80]: g=gen()

In [81]: next(g)
Out[81]: 1

In [82]: next(g)
Out[82]: 2

In [83]: next(g)
Out[83]: 3

In [84]: next(g)
----------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-85-5f315c5de15b> in <module>()
----> 1 next(g)
StopIteration:

在python中生成器有两种:

  1. 生成器表达式 把列表生成式的[]中改为(),就创建一个generator In [90]: generator_expression = (x for x in range(5)) In [91]: type(generator_expression) Out[91]: generator In [92]: next(generator_expression) Out[92]: 0 In [93]: next(generator_expression) Out[93]: 1
  2. 生成器函数 In [99]: def fib(max): ...: n,a,b =0,0,1 ...: while n < max: ...: yield b ## 关键 ...: a,b =b,a+b ...: n = n+1 ...: In [102]: type(f) Out[102]: generator In [103]: print f <generator object fib at 0x1097d1cd0> In [104]: f=fib(6) In [105]: next(f) Out[105]: 1 In [106]: next(f) Out[106]: 1 In [107]: next(f) Out[107]: 2 In [108]: next(f) Out[108]: 3 从102 步骤可以看出函数fib返回一个生成器对象,函数fib在每次调用next()的时候执行,遇到yield语句返回,再次被next()调用时候从上次的返回yield语句处继续执行,也就是用多少,取多少,不占内存。

总结

  1. 函数如果定义返回的话,必须一次返回所有的结果,因为函数只能返回一次。生成器因为使用了 yield关键字,保存执行到yield的上下文,再次调用的时候可以直接继续执行下一步操作。
  2. 生成器是特殊的迭代器,只能执行一次。
  3. 生成器和迭代器两者都是可迭代对象。
  4. yield是一个类似return 的关键字,迭代一次遇到yield的时候就返回yield后面或者右面的值。而且下一次迭代的时候,从上一次迭代遇到的yield后面的代码开始执行

推荐阅读

https://www.cnblogs.com/wj-1314/p/8490822.html

http://python.jobbole.com/87613/

http://python.jobbole.com/84527/

http://python.jobbole.com/87805/

http://python.jobbole.com/87312/

https://www.zhihu.com/question/20829330

https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014317799226173f45ce40636141b6abc8424e12b5fb27000

https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386832360548a6491f20c62d427287739fcfa5d5be1f000

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-07-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一图胜千言
  • 可迭代对象
  • 迭代器
  • 生成器
  • 总结
  • 推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档