【Python之路】特别篇--生成器(constructor)、迭代器(iterator)、可迭代对象(iterable)
生成器(constructor)
生成器函数在Python中与迭代器协议的概念联系在一起。包含yield语句的函数会被特地编译成生成器 !!!
当函数被调用时,他们返回一个生成器对象,这个对象支持迭代器接口。
不像一般的函数会生成值后退出,生成器函数在生成值后会自动挂起并暂停他们的执行和状态,他的本地变量将保存状态信息,这些信息在函数恢复时将再度有效
创建生成器方式有两种:
方法一:
s = ( x for x in range(5) )
方法二:
def foo():
print('OK')
yield 1
例子:
def g(n):
for i in range(n):
yield i **2 for i in g(5):
print(i)
要了解他的运行原理,我们来用next方法看看:
t = g(5)
print(t.__next__()) # 0
print(t.__next__()) # 1
print(t.__next__()) # 4
print(t.__next__()) # 9
print(t.__next__()) # 16
print(t.__next__()) Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
在运行完5次next之后,生成器抛出了一个StopIteration异常,迭代终止。
send(msg) 与 next()
了解了next()如何让包含yield的函数执行后,我们再来看另外一个非常重要的函数send(msg)。
其实next()和send()在一定意义上作用是相似的,区别是send()可以传递yield表达式的值进去,而next()不能传递特定的值,只能传递None进去。因此,我们可以看做
c.next() 和 c.send(None) 作用是一样的。
def g(n):
for i in range(n):
ret = yield i **2
print(ret) t = g(5)
print(t.__next__())
print(t.send('Hello')) # 0 Hello 1
需要注意的是,第一次调用时,请使用next()语句或是send(None),不能使用send发送一个非None的值,否则会出错的,因为没有yield语句来接收这个值。
send(msg) 和 next()是有返回值的,它们的返回值很特殊,返回的是yield表达式的参数 !
执行顺序是:遇到yield 先返回值,等下次再进入时再用 msg 进行赋值!!!
再来看一个yield的例子,用生成器生成一个Fibonacci数列:
def fab(max):
a, b = 0, 1
while a < max:
yield a
a, b = b, a + b for i in fab(20):
print(i) # 0 1 1 2 3 5 8 13
另一个 yield 的例子来源于文件读取。
def read_file(fpath):
BLOCK_SIZE = 1024
with open(fpath, 'rb') as f:
while True:
block = f.read(BLOCK_SIZE)
if block:
yield block
else:
return
迭代器(iterator)
for循环可以用于Python中的任何类型,包括列表、元组等等,实际上,for循环可用于任何“可迭代对象”!
迭代器是一个实现了迭代器协议的对象,Python中的迭代器协议就是有next方法的对象会前进到下一结果,而在一系列结果的末尾是,则会引发StopIteration。
任何这类的对象在Python中都可以用for循环或其他遍历工具迭代,迭代工具内部会在每次迭代时调用next方法,并且捕捉StopIteration异常来确定何时离开。
使用迭代器一个显而易见的好处就是:每次只从对象中读取一条数据,不会造成内存的过大开销。
注意:
判断迭代器的条件是:
有__iter__ 方法
有__next__ 方法
所有的生成器都是迭代器!
迭代器例子:
比如要逐行读取一个文件的内容,利用readlines()方法,我们可以这么写:
for line in open("test.txt").readlines():
print (line)
这样虽然可以工作,但不是最好的方法。因为他实际上是把文件一次加载到内存中,然后逐行打印。当文件很大时,这个方法的内存开销就很大了。
利用file的迭代器,我们可以这样写:
for line in open("test.txt"):
print (line)
这是最简单也是运行速度最快的写法,他并没显式的读取文件,而是利用迭代器每次读取下一行。
for 循环实质:
调用 __iter__ 方法将可迭代对象转换成迭代器
对迭代器对象不断调用 __next__ 方法
处理StopIteration 异常
class Fab(object):
def __init__(self, max):
self.max = max
self.n, self.a, self.b = 0, 0, 1 def __iter__(self):
return self def __next__(self):
if self.n < self.max:
r = self.b
self.a, self.b = self.b, self.a + self.b
self.n = self.n + 1
return r
raise StopIteration() '''
>>> for key in Fabs(5):
print key 1
1
2
3
5
'''
可迭代对象(iterable)
判断条件:内部具有 __iter__ 方法
from collections import Iterable,Iterator
print(isinstance(range(1),Iterable))
print(isinstance(range(1),Iterator)) print(isinstance(list(),Iterable))
print(isinstance(list(),Iterator))
【Python之路】特别篇--生成器(constructor)、迭代器(iterator)、可迭代对象(iterable)的更多相关文章
- Python的容器、生成器、迭代器、可迭代对象的家谱
前言 之前虽然写Python,但是对Python的这些概念也是模模糊糊,知道有一天,看到了一篇文章,讲的透彻,所以就写这篇作为对于这篇高文的读书笔记吧 致谢,该文作者,完全理解Python迭代对象.迭 ...
- python的生成器与迭代器和可迭代对象
来简单的说下python中的生成器和可迭代对象以及迭代器的问题.只是简单地记录一下并不涉及太深入的内容. 首先来说一下什么是生成器,先看下面的代码: #_*_ coding:utf-8 _*_ res ...
- Python生成器、迭代器、可迭代对象
把一个列表[]改成()就创建了一个生成器:generator,generator保存的是算法. 可以用于for循环的数据类型:1.集合类型:list tuple dict set str2.gener ...
- Python 生成器 (generator) & 迭代器 (iterator)
python 生成器 & 迭代器 生成器 (generator) 列表生成式 列表生成式用来生成一个列表,虽然写的是表达式,但是储存的是计算出来的结果,因此生成的列表受到内存大小的限制 示例: ...
- Python 第四篇:生成器、迭代器、装饰器、递归函数与正则表达式
一:生成器:Generator,可以理解为是一种一个函数产生一个迭代器,而迭代器里面的数据是可以通过for循环获取的,那么这个函数就是一个生成器,即生成器是有函数生成的,创建生成器使用()表示,比如g ...
- python的语法小结之生成器和迭代器
生成器: 首先介绍一下列表生成式:a=[x for x in range(10)] >>>>>>[0, 1, 2, 3, 4, 5, 6 ...
- python基础-装饰器,生成器和迭代器
学习内容 1.装饰器 2.生成器 3.迭代器 4.软件目录结构规范 一:装饰器(decorator) 1.装饰器定义:本质就是函数,用来装饰其他函数,即为其他函数添加附加功能. 2.装饰器原则:1)不 ...
- 搞清楚 Python 的迭代器、可迭代对象、生成器
很多伙伴对 Python 的迭代器.可迭代对象.生成器这几个概念有点搞不清楚,我来说说我的理解,希望对需要的朋友有所帮助. 1 迭代器协议 迭代器协议是核心,搞懂了这个,上面的几个概念也就很好理解了. ...
- 『Python』列表生成式、生成器与迭代器
1. 迭代 在 Python中, 迭代是通过 for ... in 来完成的, 而很多语言比如 C 语言, 迭代 list 是通过下标完成的. Python 的 for 循环抽象程度要高于 C 的 f ...
随机推荐
- MySQL5.7主从-GTID-mysqldump,xtrabackup搭建
1.两个空库,都是row+gtid,版本为MySQL5.7.22mydb1执行:(dba_user@localhost) [(none)]> show master status;+------ ...
- 基于keepalived搭建mysql双主高可用
目录 概述 环境准备 keepalived搭建 mysql搭建 mysql双主搭建 mysql双主高可用搭建 概述 传统(不借助中间件)的数据库主从搭建,如果主节点挂掉了,从节点只能读取无法写入,只能 ...
- SSD目标检测实战(TF项目)——人脸检测2
数据转化为VOC格式: 一.我们先看 VOC格式的数据是什么??? Annotations:存放xml 包括 文件夹信息 图片名称. 图片尺寸信息. 图片中object的信息. JPEGImage ...
- 【hash】Three friends
[来源]:bzoj3916 [参考博客] BZOJ3916: [Baltic2014]friends [ 哈希和哈希表]Three Friends [Baltic2014][BZOJ3916]frie ...
- List与Set区别
List: 元素有序放入,元素可重复 Set: 元素无序保存,元素不可重复(通过==判断,非基本类型判断的是引用地址),因为set是无序的,故只能通过迭代器循环.ps:说是无序,但是其实set中的元素 ...
- dev GridView 的组计和分组计
/// <summary> /// //添加组计 /// </summary> private void SetGroupSummary(GridView gv, string ...
- Sublime Text 3配置浏览默认路径为localhost
1.在 Sublime Text 3 中,安装 SideBarEnhancements 侧边栏增强插件.(注意:安装插件之前需要安装包管理工具,参考这里) 2.SideBarEnhancements ...
- Tika提取文件元数据
Tika可以从文件中提取元数据. 什么是元数据: 元数据是文件所提供的的附件信息即文件的属性. word文档的元数据: Tika提取元数据: 我们可以使用文件parse()方法提取元数据,传递一个空的 ...
- 查找和杀掉占用GPU显存的进程
用只有2个G的显卡跑数据就需要在训练之前先把无关进程杀掉,防止跑到一半显存满了 nvidia-smi:显示当前GPU中的线程 kill -9 PID:输入PID以结束线程
- Ubuntu 忘记系统登录密码,如何修改密码
Ubuntu 忘记系统登录密码,如何修改密码. 1.重新启动,按ESC键进入Boot Menu,选择recovery mode(一般是第二个选项). 2.在#号提示符下用cat /etc/shadow ...