迭代器,生成器
一、迭代器
python 一切皆对象
能被for循环的对象就是可迭代对象
可迭代对象: str,list,tuple,dict,set,range
迭代器: f1文件句柄
dir打印该对象的所有操作方法
1 s = 'python' 2 print(dir(s))
执行输出:
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
什么是可迭代对象:内部含有__iter__方法的对象就叫做可迭代对象
可迭代对象就遵循可迭代协议。
判断是都为可迭代对象
1 s = 'python' 2 print('__iter__' in dir(s))
执行输出:
True
迭代器
可迭代对象转化成迭代器:可迭代对象.__iter__() --->迭代器
迭代器不仅含有__iter__,还含有__next__。遵循迭代器协议。
1 l1 = [1,2,3] 2 l1_obj = l1.__iter__() # 迭代器 3 print(l1_obj)
执行输出:
<list_iterator object at 0x000001987D5EB668>
表示它是一个列表迭代器对象
1 l1 = [1,2,3] 2 l1_obj = l1.__iter__() # 迭代器 3 print('__iter__' in dir(l1_obj)) #是否含有__iter__方法 4 print('__next__' in dir(l1)) #是否含有__next__方法 5 print('__next__' in dir(l1_obj))
执行输出:
True
False
True
从结果中,可以看出l1_obj是同时含有__iter__和__next__的对象,所以它是迭代器
迭代器使用__next__获取一个值
1 l1 = [1,2,3] 2 l1_obj = l1.__iter__() # 迭代器 3 print(l1_obj.__next__()) #获取一个元素 4 print(l1_obj.__next__()) 5 print(l1_obj.__next__()) 6 print(l1_obj.__next__())
执行报错:
1
Traceback (most recent call last):
2
3
File "E:/python_script/day13/迭代器.py", line 9, in <module>
print(l1_obj.__next__())
StopIteration
多取了一个,就会报错,因为列表只有3个元素
总结:
仅含有__iter__方法的,就是可迭代对象
包含__iter__和__next__方法的,就是迭代器
二、生成器
生成器:生成器本质上是迭代器
1 l = [1,2,3] 2 l.__iter__()
#生成器的产生方式:
1,生成器函数构造。
2,生成器推导式构造。
3,数据类型的转化。
1 def func1(): 2 print(111) 3 print(222) 4 print(333) 5 return 666 6 print(func1())
执行输出:
111
222
333
666
将函数转换为生成器
1 def func1(): 2 print(111) 3 print(222) 4 print(333) 5 yield 666 6 g = func1() 7 print(g)
执行输出:
<generator object func1 at 0x000001B4C369DE60>
第一:函数中只要有yield 那他就不是一个函数,而是一个生成器
第二:g称作生成器对象。
迭代器,使用__next__取值
1 def func1(): 2 print(111) 3 print(222) 4 print(333) 5 yield 666 6 g = func1() 7 print(g.__next__()) 8 print(g.__next__())
执行报错
一个__netxt__对应一个yield
对于列表而言,for循环是从开始
对于生成器而言,它是有指针的,__next__一次,指针向前一次。它不能从头开始。
必须依次执行才行
生成器和迭代器的区别
迭代器: 有内置方法
生成器: 开发者自定义
send()
1 def generator(): 2 print(123) 3 content = yield 1 4 print('=======',content) 5 print(456) 6 yield 7 8 g = generator() 9 ret = g.__next__() 10 print('***',ret) 11 ret = g.send('hello') #send的效果和next一样 12 print('***',ret)
执行输出:
123
*** 1
======= hello
456
*** None
send 获取下一个值的效果和next基本一致
只是在获取下一个值的时候,给上一yield的位置传递一个数据
使用send的注意事项
第一次使用生成器的时候 是用next获取下一个值
最后一个yield不能接受外部的值
next 和send 功能一样,都是执行一次
send可以给上一个yield赋值。