Python内置类型(6)——生成器
上节内容说到Python的
for语句循环本质上就是通过调用Iterable可迭代对象的__iter()__方法获得一个Iterator迭代器对象,然后不断调用Iterator迭代器对象__next()__方法实现的。Iterator迭代器对象则是一个需要实现__iter__()和__next__()两个迭代器协议方法的对象。python中生成器提供了一种方便的方法来实现迭代器协议,而不需要必须实现__iter__()和__next__()两个迭代器协议方法。
生成器的定义方式有两种,一种是调用生成器函数,一种是使用生成器表达式语法。
调用生成器函数
生成器函数是指在函数体中使用yield表达式仅返回结果的函数。yield表达式仅在定义生成器函数时使用,因此只能用在函数定义的主体中。在函数体中使用yield表达式会使该函数成为生成器函数。当生成器函数被调用时,它返回一个称为生成器的迭代器,该迭代器由python自动生成。然后,生成器控制了生成器函数的执行。因为返回的生成器是一个迭代器,所以生成器函数的执行结果也就可以被循环。当生成器的的__next__方法被调用时,生成器函数的函数体内的语句开始执行,执行进行到第一个yield表达式时,立即将yield表达式的结果返回给生成器的调用者,同时将生成器函数内部的状态挂起。即保持生成器函数的执行进度,和生成器函数内的局部状态:包括局部变量的当前绑定,指令指针,内部计算栈和任何异常处理的状态。当生成器的再次调用__next__方法来时,生成器函数恢复执行,并再次执行到yield表达式返回结果再保持状态,直到无法再执行到yield表达式。此时生成器自动抛出StopIteration异常。
我们先定义一个简单生成器函数,函数功能返回数字0-9的平方数
# 生成器函数,功能返回数字0-9的平方数
>>> def squares():
for i in range(10):
yield i**2
# 使用return关键字是普通函数,使用yield关键字函数变成了生成器函数
使用参数g接收调用生成器函数squares的结果,然后分别在shell查看squares和g这两个变量的类型
>>> g = squares()
#查看squares对象类型
>>> squares
<function squares at 0x035950C0>
#查看g对象类型
>>> g
<generator object squares at 0x0358A930>
从上面可以看出变量squares是函数类型,变量g是generator类型对象,generator从字面的理解上就是生成器类型。根据上一节迭代器中提到的知识,从collection模块引入Iterator的抽象基类,验证下generator类型是不是上面说的迭代器类型。
>>> from collections import Iterator
>>> isinstance(g,Iterator)
True
验证成功,说明生成器函数的执行结果确实是生成器,一种特殊的迭代器。
>>> for i in g:
print (i)
0
1
4
9
16
25
36
49
64
81
生成器表达式
除了使用生成器函数可以得到生成器,还可以生成器表达式得到生成器表达式。生成器表达式本身看起来像列表推到, 但不是用方括号而是用圆括号包围起来:
>>> g2 = (x**2 for x in range(10))
>>> g2
<generator object <genexpr> at 0x0359AFC0>
>>> t = (1,2,3,4,5)
>>> g3 = (x**2 for x in t)
>>> g3
<generator object <genexpr> at 0x007F6180>
验证:
>>> isinstance(g2,Iterator)
True
>>> isinstance(g3,Iterator)
True
使用:
>>> for i in g2:
print(i)
0
1
4
9
16
25
36
49
64
81
>>> for i in g3:
print(i)
1
4
9
16
25
和普通迭代器相比,生成器不单简化了迭代器的定义,还在使用效率上有提升。因为生成器在循环时,生成器函数每次只会返回一个结果,然后保持内部状态,所以生成器占用的内存是很小的。以下两个测试结果,第一个直接抛出MemoryError异常,第二个只能正确计算出结果。
# 全部数据先加载在1个列表上面,内存占用高
>>> s1 = sum([i for i in range(100000000)])
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
s1 = sum([i for i in range(100000000)])
File "<pyshell#6>", line 1, in <listcomp>
s1 = sum([i for i in range(100000000)])
MemoryError
# 数据几乎不占内存
>>> s2 = sum((i for i in range(100000000)))
>>> s2
4999999950000000
Python内置类型(6)——生成器的更多相关文章
- Python内置类型性能分析
Python内置类型性能分析 timeit模块 timeit模块可以用来测试一小段Python代码的执行速度. class timeit.Timer(stmt='pass', setup='pass' ...
- Python 内置类型 dict, list,线程安全吗
近段时间发现一个 Python 连接数据库的连接是线程不安全的,结果惹得我哪哪儿都怀疑变量的多线程是否安全的问题,今天终于找到了正确答案,那就是 Python 内置类型 dict,list ,tupl ...
- 为什么继承 Python 内置类型会出问题?!
本文出自"Python为什么"系列,请查看全部文章 不久前,Python猫 给大家推荐了一本书<流畅的Python>(点击可跳转阅读),那篇文章有比较多的"溢 ...
- python内置类型详细解释
文章编写借鉴于内置类型 - Python 3.7.3 文档,主要用于自己学习和记录 python主要内置类型包括数字.序列.映射.类.实例和异常 有些多项集类是可变的.它们用于添加.移除或重排其成员的 ...
- Python——内置类型
Python定义了丰富的数据类型,包括: 数值型:int, float, complex 序列:(iterable) str, unicode, tuple, list, bytearray, buf ...
- 易被忽略的Python内置类型
Python中的内置类型是我们开发中最常见的,很多人都能熟练的使用它们. 然而有一些内置类型确实不那么常见的,或者说往往会被我们忽略,所以这次的主题就是带领大家重新认识这些"不同寻常&quo ...
- Python内置类型——set
Python中,内置类型set和frozenset用来表示集合,我们首先查看这两个类型支持的特殊对象,从而可以理解他们的特性. >>> dir(set) ['__and__', '_ ...
- 3、python内置类型(0529)
python的内置对象类型以及支持的运算 python对象的相关术语 python程序中保存的所有数据都是围绕对象这个概念展开的 程序中存储的所有数据都是对象 每个对象都有一个身份.一个类型和一个值 ...
- Python内置类型(4)--数值
Python有以下三种的数值类型: 整型(integers), 浮点型(floating point numbers), 以及 复数(complex numbers).此外,布尔是整数的子类型. 数值 ...
随机推荐
- MSTP+ VRRP 交换机的 配置过程
配置思路采用以下思路配置: 1.在处于环形网络中的交换设备上配置MSTP基本功能,包括:a.配置MST域并创建多实例,配置VLAN2映射到MSTI1,VLAN3映射到MSTI2,实现流量的负载分担. ...
- 简单了解pytorch的forward
import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from torch.autogra ...
- Codeforces Round #554 (Div. 2)-C(gcd应用)
题目链接:https://codeforces.com/contest/1152/problem/C 题意:给定a,b(<1e9).求使得lcm(a+k,b+k)最小的k,若有多个k,求最小的k ...
- elk中es集群web管理工具cerebro
cerebo是kopf在es5上的替代者 安装es虽然不能再root下运行,但是cerebro 可以 run as root is ok wget https://github.com/lmeneze ...
- ASP.NET CORE 2.0 发布到IIS,IIS如何设置环境变量来区分生产环境和测试环境
0.前言 因为给前端的测试环境是windows,所以要设置windows上的环境变量,如果上Linux就没有这篇文章了,所以大家不要在意为什么core不放在linux上. 1.网上的解决方案 a 方式 ...
- 自定义Xadmin
1.启动Xadmin INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.content ...
- AC自动机——1 Trie树(字典树)介绍
AC自动机——1 Trie树(字典树)介绍 2013年10月15日 23:56:45 阅读数:2375 之前,我们介绍了Kmp算法,其实,他就是一种单模式匹配.当要检查一篇文章中是否有某些敏感词,这其 ...
- 探索未知种族之osg类生物--渲染遍历之GraphicsContext::runOperations
osg::GraphicsContext::runOperations().我们先来看一下这个函数的执行过程. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...
- nc6 用业务插件注册来跑按钮事件
在实际开发中,有些需求是要求系统单据,编辑或者触发其他按钮来回写其他模块单据 这时候就能用业务插件方式来触发其他模块的按钮事件,而不用去模块找对应的按钮编辑事件类 package hz.bs.hzct ...
- activeMQ和spring的整合
http://www.cnblogs.com/shuai-server/p/8966299.html 这篇博客中介绍了activemq传递消息的两种方式,今天分享的是activemq框架和sprin ...