python学习之【第十三篇】:Python中的生成器
1.为什么要有生成器?
在Python中,通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。那么此时聪明的你肯定会这么想:有没有一种机制,当我们想要创建列表时,不要直接先把列表中元素全部创建出来,而是把列表元素生成的方法给我,当我要使用哪几个元素的时候我再生成,现做现卖,用多少做多少,这样多好。其实,这些前人们早就替我们想到了,所以,生成器应运而生。
2.什么是生成器?
如果列表元素可以按照某种算法推算出来,这样我们就不必创建出完整的列表,而是在循环的过程中不断推算出后续的元素,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器generator。
3.如何创建生成器?
要创建一个生成器generator,有很多种方法。我们介绍两种常用的方法:
- 简单生成器。第一种方法很简单,只要把一个列表生成式的
[]
改成()
,就创建了一个生成器generator; - 生成器函数。如果推算的算法比较复杂,用类似列表生成式无法实现的时候,还可以用函数来实现,这就是生成器函数。
4. 生成器表达式
只要把一个列表生成式的[ ]
改成( )
,就创建了一个生成器表达式generator。
创建L
和g
的区别仅在于最外层的[ ]
和( )
,L
是一个list
,而g
是一个generator
。
我们可以直接打印出list
的每一个元素,但我们怎么打印出generator
的每一个元素呢?
如果要一个一个打印出来,可以通过next()
函数获得generator
的下一个返回值:
generator
保存的是算法,每次调用next(g)
,就计算出g
的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration
的错误。
因为generator
也是可迭代对象,所以可以使用for
循环来迭代:
我们创建了一个generator
后,基本上永远不会调用next()
,而是通过for
循环来迭代它,并且不需要关心StopIteration
的错误。
5. 生成器函数
在上述的简单生成器中,元素推算的算法仅仅是x*x
,比较简单。但是如果推算的算法比较复杂,用类似列表生成式的for
循环无法实现的时候,我们可以用函数来实现。这个定义元素推算算法的函数我们称之为生成器函数。
生成器函数与普通函数有一个很重要的区别,那就是:生成器函数中需要return
的地方通通使用yield
来替换。
yield关键字
yield
关键字,其作用和return
的功能差不多,就是返回一个值给调用者,只不过有yield
的函数返回值后函数依然保持调用yield
时的状态,当下次调用的时候,在原先的基础上继续执行代码,直到遇到下一个yield
或者满足结束条件结束函数为止。
我们可以看以下例子:
首先定义一个生成器函数,调用该生成器函数时,返回一个生成器对象generator,然后用next()
函数不断获得下一个返回值,在执行过程中,遇到yield
就中断,下次又继续执行。执行3次yield
后,已经没有yield
可以执行了,所以,第4次调用next(g)
就报错。
同样的,使用生成器函数,我们基本上也不会用next()
来获取下一个返回值,而是直接使用for
循环来迭代:
def test():
print('step1')
yield 1
print('step2')
yield 2
print('step3')
yield 3
g = test()
for i in g:
print(i)
# 输出
# step1
# 1
# step2
# 2
# step3
# 3
6.生成器函数与普通函数的区别
生成器函数与普通函数主要有以下不同:
- 生成器函数包含一个或者多个
yield
; - 当调用生成器函数时,函数将返回一个对象,但是不会立刻向下执行;
- 像
__iter__()
和__next__()
方法等是自动实现的,所以我们可以通过next()
方法对对象进行迭代; - 一旦函数被
yield
,函数会暂停,控制权返回调用者; - 局部变量和它们的状态会被保存,直到下一次调用;
- 函数终止的时候,
StopIteraion
会被自动抛出;
7.应用
咋一看,生成器好像没有什么用啊,其实不然,很多情况下元素是无穷无尽的,例如斐波那契数列,杨辉三角等,这些元素都是不能被穷举的,所以我们无法将所有元素都放到一个列表里,只能是保存元素推算的算法,再进行逐个推算,这就是生成器的好处。
例如生成杨辉三角的代码,把每一行看做一个list
,试写一个generator
,不断输出下一行的list
:
1
/ \
1 1
/ \ / \
1 2 1
/ \ / \ / \
1 3 3 1
/ \ / \ / \ / \
1 4 6 4 1
/ \ / \ / \ / \ / \
1 5 10 10 5 1
# 杨辉三角
def triangles():
old_list = []
new_list = []
while True:
length = len(old_list)
if length == 0:
new_list.append(1)
else:
for item in range(length + 1):
if item == 0:
new_list.append(1)
elif item == length:
new_list.append(1)
else:
tmp = old_list[item - 1] + old_list[item]
new_list.append(tmp)
yield new_list
old_list = new_list.copy()
new_list.clear()
(完)
python学习之【第十三篇】:Python中的生成器的更多相关文章
- Python 学习笔记(十三)Python函数(二)
参数和变量 >>> def foo(a,b): #函数是一个对象 return a+b >>> p =foo #对象赋值语句.将foo函数赋值给p这个变量 > ...
- Python 学习笔记(十三)Python函数(一)
函数基础 函数:函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.Python提供了许多内建函数,比如print().可以自己创建函数,这 ...
- Python开发【第二十三篇】:持续更新中...
Python开发[第二十三篇]:持续更新中...
- Python学习笔记(十三)
Python学习笔记(十三): 模块 包 if name == main 软件目录结构规范 作业-ATM+购物商城程序 1. 模块 1. 模块导入方法 import 语句 import module1 ...
- Python学习笔记之基础篇(-)python介绍与安装
Python学习笔记之基础篇(-)初识python Python的理念:崇尚优美.清晰.简单,是一个优秀并广泛使用的语言. python的历史: 1989年,为了打发圣诞节假期,作者Guido开始写P ...
- Python开发【第十三篇】:jQuery--无内容点击-不进去(一)
Python开发[第十三篇]:jQuery--无内容点击-不进去(一)
- openresty 学习笔记番外篇:python的一些扩展库
openresty 学习笔记番外篇:python的一些扩展库 要写一个可以使用的python程序还需要比如日志输出,读取配置文件,作为守护进程运行等 读取配置文件 使用自带的ConfigParser模 ...
- openresty 学习笔记番外篇:python访问RabbitMQ消息队列
openresty 学习笔记番外篇:python访问RabbitMQ消息队列 python使用pika扩展库操作RabbitMQ的流程梳理. 客户端连接到消息队列服务器,打开一个channel. 客户 ...
- Python学习系列(四)Python 入门语法规则2
Python学习系列(四)Python 入门语法规则2 2017-4-3 09:18:04 编码和解码 Unicode.gbk,utf8之间的关系 2.对于py2.7, 如果utf8>gbk, ...
- Python学习入门基础教程(learning Python)--5.6 Python读文件操作高级
前文5.2节和5.4节分别就Python下读文件操作做了基础性讲述和提升性介绍,但是仍有些问题,比如在5.4节里涉及到一个多次读文件的问题,实际上我们还没有完全阐述完毕,下面这个图片的问题在哪呢? 问 ...
随机推荐
- Spring Boot 2.X(三):使用 Spring MVC + MyBatis + Thymeleaf 开发 web 应用
前言 Spring MVC 是构建在 Servlet API 上的原生框架,并从一开始就包含在 Spring 框架中.本文主要通过简述 Spring MVC 的架构及分析,并用 Spring Boot ...
- 基于Influxdb对InfluxDBResultMapper的一点扩展
理想很饱满,现实很骨感. 由于业务需要"灵活可配置"的功能需求,在使用java开发Influxdb查询功能的时候,遇到了一个问题,Measurement注解的名称有可能需要动态变化 ...
- 阿里云服务器ecs + tomcat + 域名解析 部署web页面
1.购买ecs:https://www.aliyun.com/product/ecs?spm=5176.12825654.eofdhaal5.2.3bf92c4aYOB7gL&aly_as=A ...
- B-线性代数-范数
目录 范数 一.Lp范数 二.L0范数 三.L1范数 四.L2范数 五.L∞范数 更新.更全的<机器学习>的更新网站,更有python.go.数据结构与算法.爬虫.人工智能教学等着你:ht ...
- Spring Security 整合JWT(四)
一.前言 本篇文章将讲述Spring Security 简单整合JWT 处理认证授权 基本环境 spring-boot 2.1.8 mybatis-plus 2.2.0 mysql 数据库 maven ...
- 安装docker 在centos中
http://www.imooc.com/article/16448 http://blog.csdn.net/jeffleo/article/details/70904368
- Maven安装和在IDEA配置Maven
一.Windows安装Maven 1.下载Maven 这里需要注意:不要去官网下载最新的版本,因为会出现与IDEA不兼容的现象. 这里提供下载地址:https://archive.apache.org ...
- 我要学并发-Java内存模型到底是什么
内存模型 在计算机CPU,内存,IO三者之间速度差异,为了提高系统性能,对这三者速度进行平衡. CPU 增加了缓存,以均衡与内存的速度差异: 操作系统增加了进程.线程,以分时复用 CPU,进而均衡 C ...
- jmeter-操作mysql
1.下载mysql驱动并放至如下目录:E:\soft\apache-jmeter-5.1.1\lib\ext 2.添加JDBC Connection Configuration(线程组-配置元件-JD ...
- JAVA动态代理 你真的完全了解Java动态代理吗?
网上讲JAVA动态代理,说的天花乱坠,发现一篇文章写的通俗易懂,特意转载过来 原文地址:https://www.jianshu.com/p/95970b089360 动态代理看起来好像是个什么高大上的 ...