python 迭代器和生成器
for循环的本质:循环所有对象,全都是使用迭代器协议。
第一部分
关于为什么要用迭代器:
优点:
1:迭代器提供了一种不依赖于索引的取值方式,这样就可以遍历那些没有索引的可迭代对象了(字典,集合,文件)
2:迭代器与列表比较,迭代器是惰性计算的,更节省内存
缺点:
1:无法获取迭代器的长度,使用不如列表索引取值灵活
2:一次性的,只能往后取值,不能倒着取值
用以下例子示例:
用索引取字典的内容:
d=[1,2,3]
i=0
while i < len(d):
print(d[i])
i+=1
其执行结果是:
1
2
3
用索引取列表的内容:
d=[1,2,3]
for i in range(len(d)):
print(d[i])
其执行结果是:
1
2
3
用迭代器的方法分别取字典的值:
#用迭代器的方式取字典的内容()不依靠索引
d={"a":1,"b":2,"c":3}
i=d.__iter__()#生成迭代器
#print(i.__next__())#打印内容
while True:
try:
print(i.__next__())#打印内容
except StopIteration:
break
其执行结果是:
a
b
c
用迭代器的方法取列表里的元素:
#用迭代器的方式取列表的内容()不依靠索引
d=[1,2,3,4,5]
i=d.__iter__()#生成迭代器
# print(i.__next__())#打印内容
while True:
try:
print(i.__next__())
except StopIteration:
break
其执行结果是:
1
2
3
4
5
总结:
(1)、可迭代的:只要对象本身有__iter__方法,那它就是可迭代的
d={'a':1,'b':2,'c':3}
d.__iter__ #iter(d)(表示d是可迭代的)
(2)、执行对象下的__iter__方法,得到的结果就是迭代器
i=d.__iter__()(i即是迭代器)
(3)3、i.__next__()(即表示的就是执行从字典d里取值)
print(i.__next__())
print(i.__next__())
print(i.__next__())
关于迭代器的使用,用以下举例:
用字典示例while循环(由于print(i.__next__())每次输出只能是一个值,但是如果字典里的元素一共有3个,打印4个print(i.__next__())就会报错)
#由于print(i.__next__())每次输出只能是一个值,但是如果字典里的元素一共有3个,打印4个print(i.__next__())就会报错,故而使用下列方法可以全部打印且不报错
d={'a':1,'b':2,'c':3}
i=iter(d)#即i=d._iter_()
while True:
try:
print(next(i))#即print(i.__next__())
except StopIteration:
break
执行结果是:
a
b
c
用列表示例while循环:
l=['a','b','c','d','e']
i=l.__iter__()
while True:
try:
print(next(i))#即print(i.__next__())
except StopIteration:
break
执行结果是:
a
b
c
d
e
用字典示例:(for循环)
d={'a':1,'b':2,'c':3}
d.__iter__#代表d是可迭代的
for k in d: #d.__iter__()#取字典里key的值
print(k)
其执行结果是:
a
b
c
用集合示例(for循环)
s={1,2,3,4}
s.__iter__()#s是可迭代的
for i in s:
print(i)
执行结果是:
1
2
3
4
用文件示例,往文件里写入内容
with open('a.txt','r') as f:
f.__iter__()#f是可迭代的
for line in f:#相当于执行的是print(f.__next__)并且不会报错
print(line)
执行结果是:
aaaaaa
bbb
cccc
eee
ffffff
关于迭代器,补充的有:
用列表示例,如果列表里有3个元素,故而打印4个print(next(i))会报错
l=[1,2,3]
print(len(l))
i=iter(l)#l是可迭代的
print(next(i))
print(next(i))
print(next(i))
print(next(i))
执行结果是:
3
1
2
3
Traceback (most recent call last):
File "C:/Users/Administrator/PycharmProjects/py_fullstack_s4/day23/迭代器.py", line 109, in <module>
print(next(i))
StopIteration
报错原因是: 因为迭代器是一次性的,只能往后取值,不能倒着取值
用列表示例,如果列表里有3个元素,print(next(i))打印3次列表里的元素,则for循环无元素可打印
l=[1,2,3]
print(len(l))#输出列表l的长度
i=iter(l)#l是可迭代的
print(next(i))
print(next(i))
print(next(i))
for x in i:
print(x)
执行结果是:
3
1
2
3
结论:for循环没有进行
用列表示例,如果列表里有3个元素,print(next(i))打印1次列表里的元素,则for循环可打印剩下的2个元素
l=[1,2,3]
print(len(l))#输出列表l的长度
i=iter(l)#l是可迭代的
print(next(i))
for x in i:
print(x)
执行结果是:
3#由print(len(l))打印的结果
1 #由print(next(i)打印的结果
2 #由for循环打印的结果
3#由for循环打印的结果
第二部分
查看可迭代对象与迭代器对象
通过from collections import Iterable,Iterator来查看
分别查看字符串、列表、元组、字典、集合、文件是否是可迭代对象与迭代器对象
s='hello'
l=[1,2,3]
t=(1,2,3)
d={'a':1}
set1={1,2,3,4}
f=open('a.txt')
示例:查看是否是可迭代对象
s='hello'
l=[1,2,3]
t=(1,2,3)
d={'a':1}
set1={1,2,3,4}
f=open('a.txt')
# 判断是否是可迭代对象,返回Ture是可迭代的
s.__iter__()
l.__iter__()
t.__iter__()
d.__iter__()
set1.__iter__()
f.__iter__()
print(isinstance(s,Iterable))
print(isinstance(l,Iterable))
print(isinstance(t,Iterable))
print(isinstance(d,Iterable))
print(isinstance(set1,Iterable))
print(isinstance(f,Iterable))
# 发现都是可迭代的
其执行结果是:
True
True
True
True
True
True
示例:判断是否是迭代器
# 判断查看是否是迭代器,返回Ture是迭代器
s='hello'
l=[1,2,3]
t=(1,2,3)
d={'a':1}
set1={1,2,3,4}
f=open('a.txt')
print(isinstance(s,Iterator))
print(isinstance(l,Iterator))
print(isinstance(t,Iterator))
print(isinstance(d,Iterator))
print(isinstance(set1,Iterator))
print(isinstance(f,Iterator))
执行结果是:
False
False
False
False
False
True
返回结果是只有文件是迭代器
第三部分
生成器就是一个函数,这个函数内包含有yield这个关键字
关于生成器yield的返回值和函数中return的返回值有何区别:
区别是:return只能返回一次函数就彻底结束了,而yield能返回多次值
yield到底有何作用:
1.yield把函数变成生成器-->迭代器
2.用return返回值能返回一次,而yield返回多次
3.函数在暂停以及继续下一次运行时的状态是由yield保存
示例说明:
def countdown(n):
print('start coutdown')
while n > 0:
yield n #有yield将函数变成了生成器
n-=1
g=countdown(5)
print(isinstance(g,Iterator))#判断g是一个迭代器
print(g)#返回内存地址
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
执行结果:
True
<generator object countdown at 0x0000000001E20620>
start coutdown
5
4
3
2
1