python生成器和python装饰器几乎平起平坐,在python世界中占有重要的地位。如果说python装饰器是为了让程序员悄无声息拓展函数功能,那么python生成器就是为了让你的代码更省资源,更高效!说实话python生成器的抽象程度和灵活程度都要比python装饰器高,功能也更加强大,所以我也只能暂时比较粗略地说句“python生成器就像一把瑞士军刀,让你的代码更加短小(简洁)精悍(有力)”。
首先我们来看一段python2环境下运行的一段代码:

#注意,在python3.x中range和xrange已被合并,这段代码运行必须在py2下!
for i in range(3):print(i)
print('----------')
for i in xrange(3):print(i)
print('----------')lst1 = [x*x for x in range(3)]
lst2 = (x*x for x in range(3))for i in lst1:print(i)
print('----------')
for i in lst2:print(i)

打印结果如下:

0
1
2
----------
0
1
2
----------
0
1
4
----------
0
1
4

看了这段代码,你可能会说:python真麻烦,有range又有xrange,有[]又有(),运行结果还一样。这不是白费事嘛?
那我们现在稍微改动下代码:

a = range(3)
b = xrange(3)
print(type(a))
print(a)
print(a[0],a[1])
print('---------')
print(type(b))
print(b)
print(b[0],b[1])
print('---------')
lst1 = [x*x for x in range(3)]
lst2 = (x*x for x in range(3))
print(type(lst1))
print(type(lst2))

打印结果如下:

<type 'list'>
[0, 1, 2]
(0, 1)
---------
<type 'xrange'>
xrange(3)
(0, 1)
---------
<type 'list'>
<type 'generator'>

这里需要说明:range()返回一个列表list,xrange()返回一个生成器;也即[]返回一个列表list而()返回一个生成器。

* 注意:用[]推导出来的是迭代器(Iterables)。用()推导出来的是生成器(Generators)。*

可迭代对象(iterable) 与 迭代器(iterator)

iterable可迭代对象是实现了__iter__()方法的对象。更确切的说,是container.__iter__()方法,该方法返回的是的一个iterator对象,因此你可以从iterable可迭代对象获得iterator迭代器。

在python中,迭代通常是通过for … in …来完成的,而且只要是可迭代对象(iterable),都能进行迭代。

例如,在下面的遍历中

for value in something

这个something就是一个可迭代对象(iterable)。比如list,string,file。

对于iterable,我们该关注的是,它是一个能一次返回一个成员的对象(iterable is an object capable of returning its members one at a time),一些iterable将所有值都存储在内存中,比如list,而另一些并不是这样,比如我们下面将讲到的iterator。

iterator(迭代器)是这样的对象:实现了无参的__next__() 方法,返回序列中的下一个元素;如果没有元素,将会抛出StopIteration异常。Python的迭代器也实现了__iter__()方法,所以一个迭代器(iterator)也是可迭代的(iterable)。

iterator.next()是iterator区别于iterable的关键了,它允许我们显式地获取一个元素.当调用next()方法时,实际上产生了2个操作:

  1. 更新iterator状态,令其指向后一项,以便下一次调用;
  2. 返回当前结果;

二者的关系如下 :

iter(可迭代对象) 生成迭代器

>>> s = 'abc'       #s是一个可迭代对象
>>> it = iter(s)    #it是一个迭代器
>>> for i in it:
...     print(i)

我们现在不用for循环遍历这个迭代器,我们尝试调用next()方法。

>>> s = 'abc'
>>> it = iter(s)
>>> next(it)
'a'
>>> s = 'abc'
>>> it = iter(s)
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):File "<stdin>", line 1, in <module>
StopIteration
>>>

除了最后一行抛出异常外,其他结果和for循环一样。也就是说,用for循环遍历迭代器(iterator)X时,会循环地调用X的next()方法取得每一次的值,直到iterator为空,返回的StopIteration作为循环结束的标志。for … in … 会自动处理StopIteration异常,从而避免了抛出异常而使程序中断。

我们对一个可迭代对象(iterable)用for … in …进行迭代时,实际是先通过调用iter()方法得到一个iterator,假设叫做X.然后循环地调用X的next()方法取得每一次的值,直到iterator为空,返回的StopIteration作为循环结束的标志.for … in … 会自动处理StopIteration异常,从而避免了抛出异常而使程序中断.

需要格外注意的是,iterator是消耗型的,即每一个值被使用过后,就消失了.因此,你可以将以上的操作2理解成pop.对iterator进行遍历之后,其就变成了一个空的容器了,但不等于None哦.因此,若要重复使用iterator,利用list()方法将其结果保存起来是一个不错的选择。
代码如下:

>>> from collections import Iterable, Iterator
>>> a = [1,2,3]   # 众所周知,list是一个iterable
>>> b = iter(a)   # 通过iter()方法,得到iterator,iter()实际上调用了__iter__(),此后不再多说
>>> isinstance(a, Iterable)
True
>>> isinstance(a, Iterator)
False
>>> isinstance(b, Iterable)
True
>>> isinstance(b, Iterator)
True
# 可见,itertor一定是iterable,但iterable不一定是itertor# iterator是消耗型的,用一次少一次.对iterator进行变量,iterator就空了!
>>> c = list(b)
>>> c
[1, 2, 3]
>>> d = list(b)
>>> d
[]# 空的iterator并不等于None.
>>> if b:
...   print(1)
...
1
>>> if b == None:
...   print(1)
...# 再来感受一下next()
>>> e = iter(a)
>>> next(e)     #next()实际调用了__next__()方法,此后不再多说
1
>>> next(e)
2

生成器概念

只要 Python 函数的定义体中有 yield 关键字,该函数就是生成器函数。调用生成器函数时,会返回一个生成器对象。也就是说,生成器函数是生成器工厂。

函数返回一个值,而生成器函数生成一个值。不仅如此,函数返回值后就退出了,而生成器可以生产多次值,生成器函数中还能出现多个yield。

如何“生成”生成器

如何产生一个生成器呢,方法有二:

1.生成器函数(generator function):带有yield关键字的函数就是生成器函数,它的返回值是个生成器。
2.生成器表达式(generator expression):而形如(elem for elem in [1, 2, 3])的表达式,称为generator expression,也能产生一个生成器。

生成器表达式生成生成器:

>>> gen = ( i for i in [2,3,4,5,6])
>>> gen
<generator object <genexpr> at 0x00000178D648D1A8>
>>> for i in gen:
...     print(i)
...
2
3
4
5
6

我们调用next()方法,也是可以的:

>>> gen = ( i for i in [2,3,4,5,6])
>>> next(gen)
2
>>> next(gen)
3
>>> next(gen)
4
>>> next(gen)
5
>>> next(gen)
6
>>> next(gen)
Traceback (most recent call last):File "<stdin>", line 1, in <module>
StopIteration

这和我们上面迭代器(iterator)的使用一毛一样!
其实,生成器(generator)就是迭代器(iterator)的一种,以更优雅的方式实现的iterator,而且完全可以像使用iterator一样使用generator。当然除了定义,定义一个iterator,你需要分别实现_ _ iter _ _ ()方法和 _ _ next_ _()方法,但generator只需要一个yield关键字就可以。

生成器函数产生生成器

>>> def gen123():
...     yield 1
...     yield 2
...     yield 3
...
>>> gen123
<function gen123 at 0x00000178D6614D08>
>>> gen123()
<generator object gen123 at 0x00000178D648D1A8>
>>> for i in gen123():
...     print(i)
...
1
2
3

这里你也能猜出来,我们调用next()方法除了会抛出异常,效果也一样:

>>> def gen123():
...     yield 1
...     yield 2
...     yield 3
...
>>> gen = gen123()
>>> next(gen)
1
>>> next(gen)
2
>>> next(gen)
3
>>> next(gen)
Traceback (most recent call last):File "<stdin>", line 1, in <module>
StopIteration

其实 ,for循环会每次隐时调用next()方法,前进到函数中的下一个yield语句处。

生成器函数执行过程

生成器另外一个黑科技是生成器中的yield语句会挂起该生成器函数的状态,保留足够的信息,以便之后从它离开的地方继续执行。

我们来看代码:

>>> def genAB():              #❶
...     print('start')
...     yield 'A'             #❷
...     print('continue')
...     yield 'B'             #❸
...     print('end')          #❹
...
>>> for i in genAB():         #❺
...     print('--->',i)       #❻
...

打印结果:

start
---> A
continue
---> B
end

❶ 定义生成器函数的方式与普通的函数无异,只不过要使用 yield 关键字。
❷ 在 for 循环中第一次隐式调用 next() 函数时(序号➎),会打印
‘start’,然后停在第一个 yield 语句,生成值 ‘A’。
❸ 在 for 循环中第二次隐式调用 next() 函数时,会打印
‘continue’,然后停在第二个 yield 语句,生成值 ‘B’。
❹ 第三次调用 next() 函数时,会打印 ‘end.’,然后到达函数定义体
的末尾,导致生成器对象抛出 StopIteration 异常。
❺ 迭代时,for 机制的作用与 g = iter(gen_AB()) 一样,用于获取
生成器对象,然后每次迭代时调用 next(g)。
❻ 循环块打印 –> 和 next(g) 返回的值。但是,生成器函数中的
print 函数输出结果之后才会看到这个输出。
❼ ‘start’ 是生成器函数定义体中 print(‘start’) 输出的结果。
❽ 生成器函数定义体中的 yield ‘A’ 语句会生成值 A,提供给 for 循
环使用,而 A 会赋值给变量 i,最终输出 –> A。
❾ 第二次调用 next(g),继续迭代,生成器函数定义体中的代码由
yield ‘A’ 前进到 yield ‘B’。文本 continue 是由生成器函数定义
体中的第二个 print 函数输出的。
❿ yield ‘B’ 语句生成值 B,提供给 for 循环使用,而 B 会赋值给变
量 c,所以循环打印出 –> B。
⓫ 第三次调用 next(it),继续迭代,前进到生成器函数的末尾。文本
end. 是由生成器函数定义体中的第三个 print 函数输出的。到达生成
器函数定义体的末尾时,生成器对象抛出 StopIteration 异常。for
机制会捕获异常,因此循环终止时没有报错。

python生成器详解相关推荐

  1. python——生成器详解

    一.生成器的由来 列表和列表生成器都无法解决内存受限的问题,列表中的所有数据都保存在内存中,以至于列表中的元素的太多了,当列表中的元素超过超过几十万甚至几百万,大量数据占用电脑内存,从而导致内存溢出, ...

  2. Python生成器详解(自定义的迭代器)

    文章目录 一 .生成器与yield 二. yield表达式应用 三. 三元表达式.列表生成式.生成器表达式 3.1 三元表达式 3.2 列表生成式 3.3 字典生成式 3.4 集合生成式 3.5 生成 ...

  3. Python 生成器详解

    1. 生成器定义 在Python中,一边循环一边计算的机制,称为生成器:generator. 2. 为什么要有生成器 列表所有数据都在内存中,如果有海量数据的话将会非常耗内存. 如:仅仅需要访问前面几 ...

  4. Python yield 详解(嚼碎了喂你,一篇精通,无需再看其他文章)

    Python yield详解 文章目录 Python yield详解 由"斐波那契"深入理解yield案例 第一个版本 第二个版本 问题的引出 第三个版本 第四个版本 总结 细化总 ...

  5. Python|SQL详解之DDL|DML|DQL|DCL|索引|视图、函数和过程|JSON类型|窗口函数|接入MySQL|清屏|正则表达式|executemany|语言基础50课:学习(14)

    文章目录 系列目录 原项目地址 第41课:SQL详解之DDL 建库建表 删除表和修改表 第42课:SQL详解之DML insert操作 delete 操作 update 操作 完整的数据 第43课:S ...

  6. python区块链开发_Fabric区块链Python开发详解

    Hyperledger Fabric是最流行的联盟区块链平台.Fabric区块链Python开发详解课程 涵盖Fabric区块链的核心概念.Fabric网络搭建.Node链码开发.Python应用开发 ...

  7. python装饰器setter_第7.27节 Python案例详解: @property装饰器定义属性访问方法getter、setter、deleter...

    上节详细介绍了利用@property装饰器定义属性的语法,本节通过具体案例来进一步说明. 一.    案例说明 本节的案例是定义Rectangle(长方形)类,为了说明问题,除构造函数外,其他方法都只 ...

  8. 【python】详解类class的继承、__init__初始化、super方法

    原文链接; https://blog.csdn.net/brucewong0516/article/details/79121179?utm_medium=distribute.pc_relevant ...

  9. python与golang_Golang与python线程详解及简单实例

    Golang与python线程详解及简单实例 在GO中,开启15个线程,每个线程把全局变量遍历增加100000次,因此预测结果是 15*100000=1500000. var sum int var ...

  10. python 最小二乘法_最小二乘法及其python实现详解

    最小二乘法Least Square Method,做为分类回归算法的基础,有着悠久的历史(由马里·勒让德于1806年提出).它通过最小化误差的平方和寻找数据的最佳函数匹配.利用最小二乘法可以简便地求得 ...

最新文章

  1. MongoDB_限制集(Capped)
  2. Linux网络编程基础(二)
  3. 安装Scrapy遇到Comand c:\users\lenovo\appdata\local\programs\python\python35\python.exe
  4. 实验详解——parted单磁盘分区并进行配额
  5. python设计模式免费_python 设计模式
  6. linux内核是否支持nfs,嵌入式命令:查看设备是否支持nfs
  7. mouseleave mouseout时候悬浮框不应该消失的时候消失了 css 解决办法
  8. ABAP和Java单例模式的攻防
  9. IImage--factory
  10. java file 字典查询_File listFiles
  11. 201903版的idea markdown无法预览的问题
  12. 《统计学》第八版贾俊平第十章方差分析知识点总结及课后习题答案
  13. Java期末复习——知识点+题库
  14. 数字功放芯片的工作原理以及应用领域
  15. microsoftonenote_Microsoft OneNote 2017 官方免费版
  16. TCP端口映射与转发软件(TCP Mapping)简介
  17. 农产品区块链溯源:疫情催使下的农产品认知升级
  18. 人生是一场盛大的遇见
  19. 如何高情商地回答同事或领导的夸奖?
  20. Unity 屏幕模糊效果

热门文章

  1. python进阶太难_Python进阶
  2. oracle数据库基础笔试题,Oracle数据库入门笔试试题及参考答案
  3. kindle刷机ttl_亚马逊卡大树kindle voyage修复刷机救砖KV死机变砖忘记密码维修
  4. tomcat打印日志乱码_针对tomcat日志乱码问题
  5. 中美线径对照表_常用线规号码与线径对照表
  6. WinRAR 6.0 永久去除广告
  7. WinRAR压缩软件无广告版
  8. lammps教程:Ovito查看晶体内部变形方法
  9. 局域网 访问计算机 软件,局域网查看工具
  10. python写数据到hive_Python数据篇之Pyhive