一、列表生成式
       在学习生成器迭代器之前先了解一下什么是列表生成式,列表生成式是Python内置的非常简单却强大的可以用来创建list的生成式。什么意思?举个例子,如果想生成列表[0,1,2,3,4,5]可以使用list(range(6)),但是如果想要生成[,,,,,]即[0,1,4,9,16,25]怎么做?

#方法一:循环
>>> L = []
>>> for x in range(6):
... L.append(x**2)
...
>>> L
[0, 1, 4, 9, 16, 25]
#方法二:列表生成式
>>> [x**2 for x in range(6)]
[0, 1, 4, 9, 16, 25]
        观察方法一、方法二可以发现,使用方法二列表生成式更为简洁、明了,方法二就是列表生成式。再来几个例子加深理解:

#计算正整数0-5之间偶数平方
>>> [x**2 for x in range(6) if x%2==0]
[0, 4, 16]

#列表生成式使用两个变量
>>> d = {'a':'1','b':'2','c':'3'}
>>> [k+'='+v for k,v in d.items()]
['a=1', 'b=2', 'c=3']
二、生成器
       通过列表生成式,可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那是否可以在循环过程中不断推算后续元素呢?这样就不必创建完整的list,从而节省大量空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

1.如何创建生成器

  方法一:创建生成器最简单的方法就是把一个列表生成式的 [] 改为 () ,就创建了一个生成器: 

#列表生成式
>>> L = [x**2 for x in range(6)]
>>> L
[0, 1, 4, 9, 16, 25] #生成器
>>> g = (x**2 for x in range(6))
>>> g
<generator object <genexpr> at 0x00000173FFBFA1A8> 注:L与g的区别仅在于最外层的[]和(),L是一个列表,而g是一个生成器。

     方法二:要把普通函数变为生成器(generator),只需把 print(b) 改为 yield b 就可以了。 如果一个函数中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个生成器(generator)。

2.如何获得生成器的每一个元素?

方法一:如果要一个一个打印出来,可以通过 next() 函数获得生成器的下一个返回值。生成器保存的是算法,每次调用next(),就计算g的下一个元素的值,直到计算到最后一个元素,没有更多元素时,抛出StopIteration错误。

#通过next()获得生成器的每一个元素
>>> g = (x**2 for x in range(6))
>>> g
<generator object <genexpr> at 0x00000173FFBFA1A8>
>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> next(g)
9
>>> next(g)
16
>>> next(g)
25
>>> next(g)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

  方法二:使用for循环

#通过for循环获得生成器的每一个值
>>> g = (x**2 for x in range(6))
>>> for i in g:
... print(i)
...
0
1
4
9
16
25

3.生成器实例

练习一:著名的斐波那契数列(Fibonacci),除第一个和第二个数外,任意一个数都可以由前两个数相加得到:1,1,2,3,5,8,13,21,34...用列表生成式写不出来,如何用函数实现?

#方法一:
>>> def fib(max):
... n,a,b = 0,0,1
... while n < max:
... print(b)
... a,b = b,a+b
... n += 1
... return 'done'
...
>>> fib(6)
1
1
2
3
5
8
'done' #注:a,b = b,a+b 相当于 t = (b,a+b) a = t[0] b = t[1]
#方法二:生成器
>>> def fib(max):
... n,a,b = 0,0,1
... while n < max:
... yield b
... a,b = b,a+b
... n += 1
... return 'done'
...
>>> f = fib(6)
>>> f
<generator object fib at 0x00000173FFBFA1A8>
>>> for i in f:
... print(i)
...
1
1
2
3
5
8

  最难以理解的就是生成器与函数的执行流程不一样。函数是顺序执行,遇到 return 语句或者最后一行函数语句就返回。而变成生成器的函数,在每次调用 next() 的时候执行,遇到 yield 语句返回,再次执行时从上次返回的 yield 语句处继续执行。

#生成器函数每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行

>>> def odd():
... print('第一步')
... yield 100
... print('第二步')
... yield 200
... print('第三步')
... yield 300
...
>>> g = odd()
>>> next(g)
第一步
100
>>> next(g)
第二步
200
>>> next(g)
第三步
300
>>> next(g)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> #odd()生成器函数,在执行过程中遇到yield就中断,下次继续执行。执行3次yield后,已经没有yield可以执行,所以第4次调用报错。

生成器总结:

a、在Python中可以简单地把列表生成式改为generator,也可以通过函数实现复杂逻辑的generator。生成器的工作原理是在for循环过程中不断计算出下一个元素,并在适当条件结束for循环。对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。

b、普通函数和生成器函数区别:普通函数调用直接返回结果,而生成器函数的“调用”实际返回一个生成器对象

#普通函数
>>> r = abs(-1)
>>> r
1 #生成器函数
>>> g = fib(6)
>>> g
<generator object fib at 0x00000173FFBFA1A8>

三、迭代器
       可以直接作用于 for 循环的数据类型有以下几种:

一类是集合数据类型,如list、tuple、dict、set、str 等;

一类是generator,包括生成器和带 yield 的generator function。

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。可以使用isinstance()判断一个对象是否是Iterable对象:

#判断一个对象是否是可迭代对象Iterable
>>> from collections import Iterable
>>> isinstance([],Iterable)
True
>>> isinstance((),Iterable)
True
>>> isinstance({},Iterable)
True
>>> isinstance('aaa',Iterable)
True
>>> isinstance((x for x in range(5)),Iterable)
True
>>> isinstance(100,Iterable)
False
>>> isinstance(True,Iterable)
False

可以被 next() 函数调用并不断返回下一个值的对象称为迭代器:Iterator。可以使用isinstance()判断一个对象是否是Iterator对象:

#判断一个对象是否是迭代器:Iterator
>>> from collections import Iterator
>>> isinstance([],Iterator)
False
>>> isinstance((),Iterator)
False
>>> isinstance({},Iterator)
False
>>> isinstance('aaa',Iterator)
False
>>> isinstance((x for x in range(5)),Iterator)
True

可以发现生成器都是迭代器(Iterator)对象,但list、tuple、dict、str虽然是可迭代对象(Iterable),却不是迭代器(Iterator)。那有没有什么方法可以使list、tuple、dict、str等可迭代对象(Iterable)变成迭代器(Iterator)?  iter() 函数可以做这件事!

#iter()将list、tuple、dict、set、str等可迭代对象变为迭代器
>>> isinstance(iter([]),Iterator)
True
>>> isinstance(iter(()),Iterator)
True
>>> isinstance(iter({}),Iterator)
True
>>> isinstance(iter('aaa'),Iterator)
True

为什么list、dict、str等数据类型不是Iterator?这是因为Python的迭代器(Iterator)对象表示的是一个数据流,迭代器(Iterator)对象可以被next() 函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

迭代器(Iterator)甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

迭代器总结:

a、凡是可作用于 for 循环的对象都是可迭代(Iterable) 类型;

b、凡是可作用于 next() 函数的对象都是 迭代器(Iterator) 类型,它们表示一个惰性计算的序列;

c、集合数据类型如list、dict、str等都是可迭代(Iterable)但不是迭代器(Iterator),不过可以通过iter()函数获得一个迭代器(Iterator)对象。

d、Python的for循环本质上就是通过不断调用next()函数实现的。

for x in [1, 2, 3, 4, 5]:
pass 实际上完全等价于: # 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:
try:
# 获得下一个值:
x = next(it)
except StopIteration:
# 遇到StopIteration就退出循环
break

四、迭代器生成器关系

1.对于可迭代对象,可以通过 iter() 函数获得迭代器对象,并且可以被next() 函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。

2.生成器是一种特殊的迭代器,生成器通过生成器函数产生,生成器函数可以通过常规的def语句来定义,但是不用return返回,而是用yield一次返回一个结果。return 与 yield 不同之处在于return返回后,函数会释放,而生成器不会。在直接调用next()方法或者用 for 语句进行下一次迭代时,生成器会从yield 下一句开始执行,直至遇到下一个 yield。

3.迭代器可以多次迭代,而生成器只能迭代一次。

#迭代器:可以多次迭代
>>> g = [x*x for x in range(5)]
>>> g
[0, 1, 4, 9, 16]
>>> for i in g:
... print(i)
...
0
1
4
9
16
>>> g
[0, 1, 4, 9, 16]
>>> for i in g:
... print(i)
...
0
1
4
9
16 #生成器:只能迭代一次
>>> f = (x*x for x in range(5))
>>> f
<generator object <genexpr> at 0x0000022BA065F0F8>
>>> for i in f:
... print(i)
...
0
1
4
9
16
>>> f
<generator object <genexpr> at 0x0000022BA065F0F8>
>>> for i in f:
... print(i)
...
>>>

生成器generator和迭代器Iterator的更多相关文章

  1. Python中生成器generator和迭代器Iterator的使用方法

    一.生成器 1. 生成器的定义 把所需要值得计算方法储存起来,不会先直接生成数值,而是等到什么时候使用什么时候生成,每次生成一个,减少计算机占用内存空间 2. 生成器的创建方式 第一种只要把一个列表生 ...

  2. python生成器(generator)、迭代器(iterator)、可迭代对象(iterable)区别

    三者联系 迭代器(iterator)是一个更抽象的概念,任何对象,如果它的类有next方法(next python3)和__iter__方法返回自己本身,即为迭代器 通常生成器是通过调用一个或多个yi ...

  3. Python之生成器(generator)和迭代器(Iterator)

    generator 生成器generator:一边循环一边计算的机制. 生成器是一个特殊的程序,可以被用于控制循环的迭代行为.python中的生成器是迭代器的一种,使用yield返回值函数,每次调用y ...

  4. 学习python第十二天,函数4 生成器generator和迭代器Iterator

    在Python中,这种一边循环一边计算的机制,称为生成器:generator 要创建一个generator,有很多种方法.第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个genera ...

  5. Python 生成器 Generator 和迭代器 Iterator

    #最近一周刚开始接触python,基本的语法,和使用特性和Java差别还是蛮大的. 今天接触到Python的迭代器和生成器有点不是很明白,所以搜索了先关资料整理了一些自己的理解和心得 简述(Profi ...

  6. 【Python之路】特别篇--生成器(constructor)、迭代器(iterator)、可迭代对象(iterable)

    生成器(constructor) 生成器函数在Python中与迭代器协议的概念联系在一起.包含yield语句的函数会被特地编译成生成器 !!! 当函数被调用时,他们返回一个生成器对象,这个对象支持迭代 ...

  7. 【python之路29】python生成器generator与迭代器

    一.python生成器 python生成器原理: 只要函数中存在yield,则函数就变为生成器函数 #!usr/bin/env python # -*- coding:utf-8 -*- def xr ...

  8. Python的生成器Generator小结

    一. 生成器的介绍 在介绍生成器(Generator)之前,我们首先需要熟悉列表生成式,列表生成式是Python内置的简单又强大的用来创建列表的生成式. 举个例子, 如果我们想生成[1*1,2*2,3 ...

  9. ES6中的迭代器(Iterator)和生成器(Generator)

    前面的话 用循环语句迭代数据时,必须要初始化一个变量来记录每一次迭代在数据集合中的位置,而在许多编程语言中,已经开始通过程序化的方式用迭代器对象返回迭代过程中集合的每一个元素 迭代器的使用可以极大地简 ...

随机推荐

  1. Labview学习之路(七)for和while的理论要点

    for循环 循环次数可以为0(N的接线端为) 终止条件:1. 完成N次循环.      2. 添加条件接线端,就像while循环的红点一样,(方法,右键点击边框,添加条件接线端) 数组通过自动索引接入 ...

  2. 小程序开发-开发模式下关闭http域名校验

    小程序开发模式去掉域名校验 我们在开发小程序的时候如果用到其他网络地址,在小程序运行时调试器会输出 : http://www.example.com 不在以下 request 合法域名列表中,请参考文 ...

  3. [LeetCode题解]79. 单词搜索

    题目描述 题目:79. 单词搜索 解题思路 遍历 首先找重复性,题目说给定单词是否存在于二维数组中,可以简化为从 (x, y) 走 n 步(n 表示单词长度),查看给定单词是否存在.然后再遍历二维数组 ...

  4. 借助FreeHttp任意篡改Websocket报文(Websocket改包)

    前言 作为Web应用中最常见的数据传输协议之一的Websocket,在我们日常工作中也势必会经常使用到,而在调试或测试中我们常常也有直接改变Websocket数据报文以确认其对应用的影响的需求,本文将 ...

  5. path.resolve和path.join的区别

    // test.js const path = require('path') let x1 = path.resolve('/目录1/目录2', '/目录3/目录4/') let x2 = path ...

  6. 初识ABP vNext(9):ABP模块化开发-文件管理

    Tips:本篇已加入系列文章阅读目录,可点击查看更多相关文章. 目录 前言 开始 创建模块 模块开发 应用服务 运行模块 单元测试 模块使用 最后 前言 在之前的章节中介绍过ABP扩展实体,当时在用户 ...

  7. 漏洞扫描工具acunetix破解安装步骤

    Acunetix 12破解版安装教程 下载地址: 链接:https://pan.baidu.com/s/1jsKkrhOcx_O7ib7FQ6pidw 提取码:pwdj 1.下载软件压缩包文件,首先点 ...

  8. Python全栈工程师系列学习之学习记录

    @ 目录 前言 Day 01 一.python的历史和种类 二.安装python解释器以及配置环境变量 三.变量.常量和注释 Day 02 Day 03 Day 04 Day 05 Day 06 一. ...

  9. 再不迁移到Material Design Components 就out啦

    翻译自国外文档加自己理解 原文 我们最近宣布了 Material Design Components(MDC)1.1.0 ,这是一个库更新,为您的 Android 应用程序带来了 Material T ...

  10. 设计模式 | Catalog设计模式,抵御业务方需求变动

    大家好,这是一个全新的专题--设计模式. 其实可以选择的专题还有好几个,为什么选择设计模式呢?原因也很简单,首先是设计模式简单.易学.干货的文章固然好,但是普适性往往不强.另外一个很重要的点就是设计模 ...