Python内置类型(6)——生成器
2017-12-21 13:53
363 查看
上节内容说到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中内置数据类型list,tuple,dict,set的区别和用法
- Python内置的数据类型--list,tuple
- Python中内置数据类型list,tuple,dict,set的区别和用法
- Python内置数据类型
- Python内置数据类型详解
- python内置数据类型
- Python 数据类型以及迭代器和生成器
- 内置类型string函数python2.7.11
- Python3中内置类型bytes和str用法及byte和string之间各种编码转换
- 今天开始学python(内置数据类型)
- python基础-内置数据类型
- python内置对象类型转换简记
- python学习之内置数据类型
- 【Python】内置数据类型
- Python基础2(内置数据类型及转换)
- Python内置数据类型之Tuple
- Python核心数据类型(内置对象)—— 列表(list)
- python基础教程之基本内置数据类型介绍
- python内置类型
- python的内置数据类型