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节里涉及到一个多次读文件的问题,实际上我们还没有完全阐述完毕,下面这个图片的问题在哪呢? 问 ...
随机推荐
- Mariadb 基于Mycat实现读写分离
环境:Mariadb主:192.168.200.129 Mariadb从:192.168.200.114 Mycat :192.168.200.112 (1) 安装jdk,先查看本机是 ...
- 基于Linux的kfifo移植到STM32(支持os的互斥访问)
基于Linux的kfifo移植到STM32(支持os的互斥访问) 关于kfifo kfifo是内核里面的一个First In First Out数据结构,它采用环形循环队列的数据结构来实现:它提供一个 ...
- java生成32位UUID
java生成32位UUID,具体代码如下: package com.fxsen.uuid; import java.util.UUID; /** * Copyright: Copyright (c) ...
- 程序员IT狗有什么副业可以做呢?
1. 开篇 副业有很多,全网有做什么公众号.闲鱼.手机卡,各种各样的都有,大部分是骗子,小部分是通过自己的努力,获得了成功. 从年初就开始实践如何做一个自由职业者,近大半年有一些感受正好一起分享交流一 ...
- 分布式FastDFS集群部署
FastDFS FastDFS的作者余庆在其 GitHub 上是这样描述的:"FastDFS is an open source high performance distributed f ...
- opencv::直方图均衡化
直方图均衡化 图像直方图: 是指对整个图像像在灰度范围内的像素值是指对整个图像像在灰度范围内的像素值(~)统计出现频率次数,据此生成的直方图,称为图像直方图-直方图. 直方图反映了图像灰度的分布情况. ...
- EFK教程 - EFK快速入门指南
通过部署elasticsearch(三节点)+filebeat+kibana快速入门EFK,并搭建起可用的demo环境测试效果 作者:"发颠的小狼",欢迎转载与投稿 目录 ▪ 用途 ...
- ESP32 开发之旅② Arduino For ESP32说明
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- 记录一次gdb debug经历
目录 问题描述 查看core文件 使用gdb查看core文件 总结 问题描述 今天在写代码时,运行时奔溃了.segment fault,而且是在程序退出main()函数后,才报的. 唯一的信息是:Se ...
- Python中文件路径名的操作
1 文件路径名操作 对于文件路径名的操作在编程中是必不可少的,比如说,有时候要列举一个路径下的文件,那么首先就要获取一个路径,再就是路径名的一个拼接问题,通过字符串的拼接就可以得到一个路径名.Pyth ...