python基础之三大器中迭代器和生成器
迭代器
迭代对象: 在python中,但凡内部含有iter方法的对象,都是可迭代对象。
**迭代器: 在python中,内部含有__Iter__方法并且含有__next__方法的对象就是迭代器。**
可迭代对象
str
list
set
dic
python中规定,只要具有
__ iter__()
方法就是可迭代对象str.__iter__()# list.__iter__()# tuple.__iter__()# dict.__iter__()# set.__iter__()
将可迭代对象转换成迭代器
lis = lst.__iter__()
# print(lis.__next__()) # 下一位 # print(lis.__next__()) # 下一位 # print(lis.__next__()) # 下一位 # print(lis.__next__()) # 下一位 有多少元素就能next 多少次 超过范围报错
文件句柄就是一个迭代器 # f = open("usrinfo","a",encoding="utf-8")
while模拟for的内部循环机制
将可迭代对象转换成迭代器,然后利用next进行取值,最后利用异常处理处理StopIteration抛出的异常。
s = "alex" s1 = s.__iter__() while True: try: # 尝试着运行一下缩进体中的代码 print(s1.__next__()) except StopIteration: break
可迭代对象如何转化成迭代器,并且取值
方法一:
lst = [1,2,3,4] l = lst.__iter__() print(1.__next__()) #1 print(1.__next__()) #2 print(1.__next__()) #3 print(1.__next__()) #4 方法二 lst = [1,2,3,4] l = iter(lst) print(next(l)) #1 print(next(l)) #2 print(next(l)) #3 print(next(l)) #4 #推荐
python2 和python3
py2没有__iter__() 有iter() py3 有__iter__() 有iter()
可迭代对象优点和缺点:
#优点 1.使用灵活(每个可迭代对象都有自己的方法) 2.能够直接查看元素的个数 #缺点 占内存 应用:内存空间大,当数据量比较少,建议使用可迭代对象
迭代器的优缺点及应用
#具有__iter__()和__next__()方法就是一个迭代器 #优点 节省内存 #缺点 1 只能向一个方向执行,不能退回 2 一次性的 3 不能灵活操作,不能直接看元素的个数 应用:当你的数据量过大,大到足以撑爆你的内存或者你以节省内存为首选因素时,将数据集设置为迭代器是一个不错的选择。(可参考为什么python把文件句柄设置成迭 代器)。
时间换空间:迭代器,生成器,用大量的时间来节省空间
空间换时间:可迭代对象,用大量空间来节省时间
lst = [1,2,3,4] l = iter(lst) #print(l) 输出结果是迭代器的内存地址 <list_iterator object at 0x0000018117F0BA58> for i in l:# for循环可以直接去循环迭代器 print(i)
迭代器也是一个可迭代对象
生成器
生成器的本质就是一个迭代器
最大的区别:
- 迭代器:文件句柄,通过数据转换 python自带提供
- 生成器:程序员自己实现
生成器的目的:不在通过数据转换实现,而是通过代码编写实现
生成器的定义:
1.基于函数实现的生成器
2.表达式实现生成器
这是一个函数 def func(): print(1) return 5 print(func()) 这是一个函数
这是一个生成器
def func(): print(1) yield 5 print(func()) 创建一个生成器对象 <generator object func at 0x0000025A8B022EB8>
表达式形式的生成器
gen = (i**2 for i in range(10)) print(next(gen)) 博客推导式那里细讲
函数print(func()) 得到的是return返回的值,而生成器print(fun()) 得到的是生成器对象的内存地址
补充运行代码情况
# def func(): # print(foo) 报错 # func() # def func(): # print(foo) 不报错 因为计算机在查看代码时候会进行 1 语法分析 2词法分析 第一个是语法没有错,foo没有定义,但是他调用了,语法分析时没有问题,但是执行调用使用词法分析就 会报错 第二个虽然没定义foo 但是语法没有错误,词法错误,但是函数体没有调用,故不会报错
生成器怎么用:
特点:惰性机制
yield 和 return部分功能很像
- 版一
def func( ): yield 1 #记录执行位置的 yield 2 yield 3 g = func() #获取的是生成器的内存地址 print(next(g)) #1 print(next(g)) #2 print(next(g)) #3 惰性机制,不next 不往下执行
- 版二
def func(): yield 1 yield 2 yield 3 g =func() g1 =func() g2= func() print(g,g1,g2) 输出三个<generator object func at 0x00000133E5DA7990> 只不过后边的地址不一样,说明创建了三个生成器
def func(): yield print(func().__next__()) NONE #得到是yield 返回的NONE
def func(): yield [1,2,3,4,5] print(func().__next__(),type(func().__next__())) 得到的是[1,2,3,4,5] 类型是List
def func(): !!!!!这个有意思 结果是 1 NONE <class 'function'> def foo(): print(1) yield foo g = func().__next__() print(g(),type(g))
def func(): yield 1,2,3,4,5 print(123) yield 111 g = func() print(next(g)) print(next(g)) 输出结果(1,2,3,4,5) 123 111 yield惰性 next往下走
yield from def func(): yield [1,2,23,54,2] #将列表整体返回 yield from [1,2,23,54,5] #将列表中的元素逐个返回 g = func() print(next(g)) [1,2,23,54,2] print(next(g)) 1 print(next(g)) 2 print(next(g)) 23 print(next(g)) 54 print(next(g)) 5
总结:
在我理解就是生成器就是人造的迭代器,通过next取值,用时间换空间!
生成器一定是一个迭代器,但是迭代器不一定是一个生成器
迭代器和生成器的优点:
节省内存
迭代器和生成器的缺点
1.不能直接使用元素 2.不能直观查看元素的个数 3.使用不灵活 4.稍微消耗时间 5.一次性的,不能逆行
当数据量特别大的时候,一定要记得用生成器
区分迭代器和生成器:
lst = [1,2,3] print(lst.__iter__()) def func(): yield 1 print(func()) # 看内存地址 结果会显示iterator是迭代器 generator是生成器
yeild
return一般在函数中只设置一个,他的作用是终止函数,并且给函数的执行者返回值。
yield在生成器函数中可设置多个,他并不会终止函数,next会获取对应yield生成的元素。
yield 能返回多个,以元组的形式储存
yield 能返回各种数据类型
yield 能写多个并且都执行
yield 能够记录执行位置
yield 后边不写内容,默认返回NONE
- yield 都是将数据一次性返回
yield from 是将数据逐个返回
可迭代对象: 具有__iter__()方法的就是一个可迭代对象 迭代器: 具有__iter__()和__next__()方法就是一个迭代器 生成器: 基于函数创建的生成器,函数体中必须存在yield