一迭代器
python 一切皆对象
能被 for 循环的对象就是可迭代对象.
可迭代对象: str, list, tuple, dict, set , range
迭代器: f1 文件句柄
dir 打印该对象的所有操作方法:
- s = 'python'
- 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__方法的对象就叫可迭代对象, 可迭代对象就遵循可迭代协议.
如何判断两种方式:
第一种:
- s = 'python'
- print('__iter__' in dir(s))
执行输出:
True
第二种:
- from collections import Iterable #此模块判断是否为可迭代对象
- l = [1,2,3,4]
- print(isinstance(l,Iterable))
执行输出:
- True
- from collections import Iterable
- l = [1, 2, 3, 4]
- print(type(l))
- print(isinstance(l,list)
执行输出:
- <class 'list'>
- True
type 只能判断是什么类型
isinstance 判断方面更广, 不仅能判断类型, 还能判断是是否可迭代
迭代器
可迭代对象转化成迭代器: 可迭代对象.__iter__()--> 迭代器
迭代器不仅含有__iter__, 还含有__next__. 遵循迭代器协议.
- l1 = [1,2,3]
- l1_ojb = l1.__iter__() #迭代器
- print(l1_ojb)
执行输出:
<list_iterator object at 0x000001987D5EB668>
表示它是一个列表迭代器对象
- l1 = [1,2,3]
- l1_obj = l1.__iter__()# 迭代器
- print('__iter__' in dir(l1_obj)) #是否含有__iter__方法
- print('__next__' in dir(l1)) #是否含有__next__方法 这里是 dir 里给的是 l1 这个列表. 而不是 l1_obj
- print('__next__' in dir(l1_obj))
执行输出:
True
False
True
从结果中, 可以看出 l1_obj 是同时含有__iter__和__next__的对象, 所以它是迭代器
迭代器使用__next__获取一个值
- l1 = [1,2,3]
- l1_obj = l1.__iter__() # 迭代器
- print(l1_obj.__next__()) #获取一个元素
- print(l1_obj.__next__())
- print(l1_obj.__next__())
- 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 个元素
使用 for 循环方式
- l1 = [1,2,3]
- l1_ojb = l1.__iter__() #转换为迭代器
- for i in l1_ojb:
- print(i)
执行输出:
1
2
3
for 循环的内部机制, 就是使用__next__方法执行的. 为什么没有报错呢? 它内部有异常处理机制.
总结:
仅含有__iter__方法的, 就是可迭代对象
包含__iter__和__next__方法的, 就是迭代器
判断迭代器的 2 种方法:
第一种:
- l1 = [1,2,3]
- l1_ojb = l1.__iter__()# 转换为迭代器
- print('__iter__' in dir(l1_ojb))
第二种:
- l1 = [1,2,3]
- l1_obj = l1.__iter__()
- from collections import Iterable
- print(isinstance(l1_obj,Iterable))
返回 True, 就表示它是的
迭代器的好处:
1. 节省内存空间.
2. 满足惰性机制.
3. 不能反复取值, 不可逆.
不可逆, 表示, 已经取过值, 不能再次取, 他只能取下一个.
for 处理机制
- l2 = [1,2,3,4,5,6,7,8]
- for i in l2:
- print(i)
1. 将可迭代对象转化成迭代器
2. 内部使用了__next__方法取值
3. 运用了异常处理去处理报错
迭代器的好处, 就是节省内存空间
好的程序员, 会在内存优化化方面考虑, 比如迭代器
使用 while 循环, 指定用__next__方法遍历列表
- l2 = [1,2,3,4,5,6,7,8]
- l2_obj = l2.__iter__() #1. 将可迭代对象转化成迭代器
- while True:
- try:
- i = l2_obj.__next__() #内部使用__next__方法取值
- print(i)
- except Exception: #运用了异常去处理报错
- break
try 里面的代码, 出现报错, 不会提示红色文字.
Exception 可以接收所有报错, 表示报错的时候, 该怎么处理, 这里直接使用 break 跳出循环
面试题:
使用 while 循环去遍历一个有限对象
直接使用上述代码即可.
二, 生成器
生成器: 生成器本质上就是迭代器
- l = [1,2,3]
- l.__iter__()
- # 生成器的产生方式:
1. 生成器函数构造
2. 生成器推到式构造
3. 数据类型转化
- def func1():
- print(111)
- print(222)
- print(333)
- return 666
- print(func1())
执行输出:
- 111
- 222
- 333
- 666
将函数装换为生成器
- def func1():
- print(111)
- print(222)
- print(333)
- yield 666
- g = func1()
- print(g)
执行输出:
<generator object func1 at 0x0000023C67C2C3B8>
第一: 函数只要有 yield 那他就不是一个函数, 而是一个生成器
第二: g 称作生成器对象.
迭代器, 使用__next__取值
- def func1():
- print(111)
- print(222)
- print(333)
- yield 666
- g = func1()
- print(g.__next__())
- print(g.__next__())
执行报错
一个__netxt__对应一个 yield. 而这里多了一个
案例:
生成 10000 套服装
一个厂商直接生产出 10000 套了
- def func1():
- for i in range(1,10001):
- print('Selected 服装 %d' % i)
- func1()
执行后输出:
Selected 服装 1
......
......
Selected 服装 10000
我先生产 50 套给你
- def func1():
- for i in range(1,10001):
- yield 'Selected 服装 %d 套'% i
- g = func1()
- for i in range(1,51): #我先生产 50 套
- print(g.__next__())
执行后输出:
Selected 服装 1
......
......
Selected 服装 50
最终老板只要 200 套
先 50 套, 再 150 套
- def func1():
- for i in range(1,10001):
- yield 'Selected 服装 %d 套' % i
- g = func1()
- # 先给你生产 50 套, 待后续谈妥善后在给你生产 150 套
- for i in range(1,51):
- print(g.__next__())
- for j in range(150):
- print(g.__next__())
执行后输出:
Selected 服装 1
......
......
Selected 服装 200
对于列表而言, for 循环是从 0 开始的.
对于生成器而言, 它是由指针的,__next__一次, 指针向前一次. 它不能从头开始.
必须依次执行才行
生成器和迭代器的区别
迭代器: 有内置方法
生成器: 开发者自定义
- send
- def generator():
- print(123)
- content = yield 1
- print('=====',content)
- print(456)
- print('***',ret)
- yield
- g = generator()
- ret = g.__next__()
- print('***',ret)
- ret=g.send('hello')
- print('***',ret)
- 123
- *** 1
- ===== hello
- 456
- *** 1
- *** None
send 获取下一个值的效果和 next 基本一致
只是在获取下一个值的时候, 给上一个 yield 的位置传递一个数据
使用 send 的注意事项:
第一次使用生成器的时候 是用 next 获取下一个值
最后一个 yield 不能接受外部的值.
next 和 send 功能一样, 都是执行一次
send 可以给上一个 yield 赋值.
默写内容:
1. 什么是可迭代对象, 什么是迭代器
答:
内部含有__iter__方法的对象就叫做迭代对象.
内部必须有__iter__方法和__next__方法的对象, 叫做迭代器.
2. 可迭代对象如何转化成迭代器
答,:
转化成迭代器: 可迭代对象.__iter__()--> 迭代器
例如:
- l1 = [1,2,3]
- l1_obj = l1.__iter__()
3. 迭代器如何取值
答
迭代器使用__next__() 方法
4. 什么是生成器, 如何写一个生成器? 生成器是怎么取值?
答:
生成器, 即生成一个容器. 在 python 中, 一边循环, 一边计算的机制, 称之为生成器
生成器示例:
- def fun1():
- yield 1
生成器使用__next__() 方法取值, 或者 for 循环
来源: http://www.bubuko.com/infodetail-2550084.html