生成器和迭代器
迭代器
迭代器的作用:迭代器的目的就是为了“循环”,更加严谨一点,叫做"遍历"
迭代器是实现了对象中数据循环的操作方法,本质上是抽象的概念,经常把以下概念认为是迭代器:
对象中的next(),他是实现了迭代器的操作
具有迭代器的可迭代对象本身,他只是承载了迭代器具体操作的对象而已
列表和元组
列表和元组是有序的序列,所以可以直接通过索引获取每个值,索引+1就可以逐个获取,在内存中的操作就是将内存地址+1 获取下一个元素的内存地址,然后读取出来
集合和字典
集合和字典作为无序序列,无法通过索引获取每个值,这个时候就需要定义迭代器了。
迭代:概念(iteration)
迭代就是执行重复的特定的任务,直到任务完成位置。
相当于我们盖房子,今天添一块砖,明天加一张瓦,直到防止改完为止。这里每天的工作就是一次迭代。
迭代器协议(iterator protocol)
如果一个对象中包含了next()的魔术方法,那么这个对象就有了迭代器,这个对象不是迭代器
自定义迭代器:
#自定义一个迭代器
class DDQ:
def __init__(self):
#添加一个计数变量
self.index = 0
#定义了一个迭代器,该方法实现了迭代器,不是迭代器本身
def __next__(self):
i = self.index
if i<10:
#更新计数变量
self.index +=1
#为一次迭代返回值
return i
else:
#停止迭代
raise StopIteration
该迭代器制作完毕,并没有什么卵用,除非手动调用next()才可以迭代
ddq = DDQ()
#使用迭代器迭代数据
for i in ddq:
print(i)
#错误信息:TypeError: 'DDQ' object is not iterable 该对象不可以迭代
以上操作实现了一个不可以迭代的迭代器!
可迭代协议 (iterator protocol)
可迭代协议包含2条要求:
1.对象中必须实现__iter__()的方法
2.这个__iter__()方法必须返回一个迭代器
注意:具有迭代器不一定可以迭代,有些对象没有实现可迭代操作
实现可迭代协议:
class DDQ:
def __init__(self):
#添加一个计数变量
self.index = 0
#定义可迭代协议
def __iter__(self):
return self
#定义了一个迭代器,该方法实现了迭代器,不是迭代器本身
def __next__(self):
i = self.index
if i<10:
#更新计数变量
self.index +=1
#为一次迭代返回值
return i
else:
#停止迭代
raise StopIteration
#for..in迭代对象
kddq = DDQ()
for i in kddq:
print(i)
大功告成:我们实现了可迭代协议,所以该对象可以迭代
完整的说法:这是一个具有迭代器(next)的可迭代(iter)对象(类)
迭代器相关的函数
iter() 获取一个对象的迭代器
格式:iter(对象)
返回:迭代器
next() 进行一次迭代操作
格式:next(迭代器)
返回值:迭代器返回值
迭代器的操作
1.手动迭代
next(迭代器) 获取第1个值
next(迭代器) 获取第2个值
...
next(迭代器) 获取第n个值
...
迭代终止
2.循环迭代
for .. in 可迭代对象:
在循环中使用next(迭代器)实现了迭代。
总结:
1.一般情况下,迭代器都是可迭代的。但是也有不可以迭代的。
2.字典和集合中一定是有迭代器,并且可以迭代
生成器:
生成器可以理解为一种数据类型,他并不是,因为他也是迭代器的一种,是一种非常特殊的迭代器
生成器本身实现了iter 可迭代协议,但是并没有实现迭代器协议?、
迭代器协议呢?
生成器就是要实现迭代器协议,但是语法和操作和迭代器有很大的区别。
生成器的优点:
生成器对python中的延迟操作提供了支持。操作不需要一次完成,只需要在需要的时候进行操作即可
延迟操作的别名:惰性求值
处理大数据和超大文件等操作,生成器非常有效的。
生成器分类:
1.生成器表达式
元组内涵/元组推导式 的结果就是制作一个生成器,生成器的结果是一个对象
#生成器/元组推导式
tuple1 = (1,2,3,4,5,6,7,8,9)
scq = (i for i in tuple1)
print(scq)
2.生成器函数
正常声明函数就可以了,生成器中使用yield语句而不是return语句,生成器的结果是一个对象
#h函数生成器
def myfunc():
yield 1
yield 2
yield 3
yield 4
scq2 = myfunc()
print(scq2)
调用生成器:
1.手动调用
next(生成器) 获取第1个值
next(生成器) 获取第2个值
...
next(生成器) 获取第n个值
...
迭代终止
2.循环调用
for .. in 可迭代对象:
在循环中使用获取yield的值实现了迭代。
生成器函数
send() 向生成器中传入一个数据
格式:生成器.send(值)
在生成器函数中
变量 = (yield 其他变量)
close() 关闭生成器结束迭代
格式:生成器.close()
效率问题:
不能单独进行比较,这两个操作适用于不同的环境。
对于小数据而言,使用迭代器操作更加方便可靠。
对于大数据而言,使用迭代器容易玩崩,推荐使用生成器
在遍历10个G的文件时,内存只有2个G
使用迭代器是无法操作的,迭代器需要将数据预先准备好才可以迭代,2G内存装下10G文件那就呵呵了~!
使用生成器是非常理想,生成器处理多少文件数据,就占用多少内存,处理完这点数据还会清空,在此利用内存,2G内存处理10G文件绰绰有余
最后!生成器的缺陷
生成器只能迭代一次!
网友评论