Python —— 生成器、迭代器
Python —— 生成器、迭代器
方法
判断一个对象是否是可迭代对象Iterable
1 from collections import Iterable 2 li = [1,2,3,4] 3 print(isinstance(li,Iterable)) 4 # 结果为True,说明是可迭代对象 5 num = 1234 6 print(isinstance(num,Iterable)) 7 # 结果为False,说明不是可迭代对象
判断一个对象是否是迭代器 Iterator
1 from collections import Iterator 2 li = [1,2,3,4] 3 print(isinstance(li,Iterator)) 4 # 结果为False,说明不是迭代器 5 g_li = [1,2,3,4].__iter__() 6 print(isinstance(g_li,Iterator)) 7 # 结果为True,说明是迭代器
三、可迭代对象:含有双下iter(__iter__)方法的对象就是可迭代对象
迭代器:同时含有 __iter__ 和 _-next__ 方法的对象是迭代器
生成器就是迭代器,只不过是pythoner自己开发的迭代器
查看数据类型可用的方法: dir():
1 li = [1,2,3] 2 print( dir(li) )
3 #运行结果 ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__',
'__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear',
'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
四、迭代器
1、可迭代协议:只要包含了双下iter方法的数据类型就是可迭代的。迭代协议是数据类型与python解释器定下来的协议
可迭代对象是不能取出数的,迭代器实现了从其中一个一个的取出数来
1 li = [1,2,3] 2 print(li.__iter__()) # __iter__方法将可迭代对象转换为迭代器
2、迭代器协议:迭代器中有__next__ 和 __iter__ 方法
3、从迭代器中取值:
1 g = [1,2,3].__iter__() 2 print(g.__next__()) # 每取完一个数,光标移动,下一次取数光标从该位置开始取下一个值 3 print(g.__next__()) 4 print(g.__next__())
5 print(g.__next__()) # 当迭代器中数据取完时,程序报错,StopIteration(终止迭代)
4、迭代器和可迭代对象的关系:
# 迭代器包含可迭代对象
# 迭代器 = 可迭代对象.__iter__()
5、为什么要使用迭代器,迭代器的本质是什么?
# 迭代器能够对python中的基本类型数据进行统一的遍历,不需要关心每一个值分别是什么
# 可以节省内存 -- 惰性运算:列表会将所有的值放入内存。
6、迭代器的种类:
# 1、本身就是迭代器,如文件句柄:
# 2、可迭代对象.__iter__()
异常处理
迭代器中元素个数是有限的,当取值次数超过元素个数时,程序报错:StopIteration
报错:
1 li = [1,2,3] 2 li_g = li.__iter__() 3 while True: 4 for i in range(100): 5 print(li_g.__next__())
# 运行结果:
1
2
3
Traceback (most recent call last):
File "D:/oldboy/s7课上所有 - 老师版/day14/3迭代器.py", line 88, in <module>
print(li_g.__next__())
StopIteration
解决办法如下:try - except
1 li = [1,2,3] 2 li_g = li.__iter__() 3 while True: 4 for i in range(100): 5 try: 6 print(li_g.__next__()) 7 except StopIteration: 8 break
# 运行结果:
1
2
3
生成器/两种
1、生成器函数
含有 yield 关键字的函数叫生成器函数,生成器函数执行时返回一个生成器
① 生成器的基本格式
1、yield后不写内容,得到结果None
2、不写yield,函数是普通函数。
3、只有一个yield,作用同return,所以生成器函数至少要包括两个yield。
1 def generator(): 2 print(111) 3 yield 333 4 print(222) 5 yield 444 6 7 g = generator() # 直接调用生成器函数,会得到一个生成器 g ,print后得到的是生成器的地址 8 print(g) 9 for i in g: # 每次循环,得到一个yield对应的值,光标移动到当前位置,下次循环从光标位置开始寻找下一个yield 10 print(i)
# 运行结果:
# <generator object generator at 0x000001B6DC96D048>
111
333
222
444
② 利用for循环实现 yield
虽每循环一次,就有一个yield
1 def clothing(): 2 for cloth in range(1,2001): 3 yield "已做完第 %s 件校服。"% cloth 4 5 g = clothing() 6 for i in range(30): 7 print(g.__next__())
# 运行:
已做完第 1 件校服
已做完第 2 件校服
...
已做完第 30 件校服
③ 监控文件的输入,并打印出输入内容
1 import time 2 def tail(filename): 3 f = open(filename,encoding='utf-8') 4 f.seek(0,2) #将文件的光标移到最后 5 while True: 6 line = f.readline() 7 if not line: 8 time.sleep(0.1) 9 continue 10 yield line 11 12 tail_g = tail('demo') 13 for line in tail_g: 14 print(line,end='')
2、生成器表达式
3、yield from
1 def func(): 2 for i in [1,2,3]: 3 yield i 4 for j in "ABCD": 5 yield j 6 7 def func(): 8 yield from [1,2,3] 9 yield from "ABCD"