迭代器协议
- 迭代器协议:对象必须提供一个
netx
方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration
异常,
以终止迭代(只能往后不能往前退) - 可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义一个
__iter__()
方法) - 协议:是一种约定,可迭代对象实现了迭代器协议,python的内部工具(
如for循环,sum,min,max函数等)是用迭代器协议访问对象。
for循环工作机制
for循环的本质:循环所有对象,全都是使用迭代器协议。
对象(字符串、列表、字典、集合、文件)内部存在__iter__()
方法,
例如I = [1, 2, 3]
I 为 列表,I.__iter__()
为 可迭代对象。
实践1-调用列表的__iter__()
方法查看其类型是什么?
I = [1, 2, 3] |
运行结果
Out[6]: list_iterator |
通过type()查看I.__iter__()
为列表迭代器。
实践2-列表迭代器是否真的存在__next__()
方法?
I = [1, 2, 3] |
实践3-for循环列表迭代器打印每一个元素
I = [1, 2, 3] |
通过for循环列表迭代器打印列表中的每一个元素。
实践4-通过索引去遍历列表的每一个元素
I = [1, 2, 3] |
既然通过索引可以遍历列表中所有的元素,为什么还要用迭代的方式呢?
- 迭代对象可以节省内存空间;
- 不是所有对象都像list一样是有顺序有索引的。
next()
方法
next()
本质就是调用了可迭代对象的__next__()方法
实践1-通过next()
获取列表的每一个元素
I = [1, 2, 3] |
三元运算
name = 'superman' |
列表解析
一般写法
man_list = [] |
列表解析,将所有的元素都放到了内存中。
[i for i in range(10)] |
三元表达式,可以小于三元,但是不能大于三元。
[i for i in range(10) if i > 5] |
实践1-生成1000万个数字
[i for i in range(1000)] |
生成器表达式
- 把列表解析的
[]
换成()
得到的就是生成器表达式; - 列表解析与生成器表达式都是
实践1-生成1000万个数字
(i for i in range(1000)) |
生成器
一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator);如果函数中包含yield语法,那这个函数就会变成生成器;
def func(): |
上述代码中:func是函数称为生成器,当执行此函数func()时会得到一个迭代器。
temp = func() |
实践1-普通函数实现斐波拉契数列
def fib(max): |
实践2-生成器实现斐波拉契数列
def fib2(max): |
可以看出返回的<generator object fib2 at 0x000001EF306570F8>
是一个生成器对象,并且生成器内部的东西没有马上执行,而是执行到yield的时候就返回一个迭代器。
总结
迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退。另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件
特点:
访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容
不能随机访问集合中的某个值 ,只能从头到尾依次访问
访问到一半时不能往回退
便于循环比较大的数据集合,节省内存
- 推导式有, 列表推导式, 字典推导式, 集合推导式, 没有元组推导式
- 生成器表达式:
(结果 for 变量量 in 可迭代对象 if 条件筛选)
- 生成器表达式可以直接获取到⽣成器对象. ⽣成器对象可以直接进行for循环. ⽣成器具有惰性机制.
- 集合推导式和字典推导式很是类似,记住一个小技巧能够快速区分那个是字典那个是集合
- 字典推导式前面的结果是有个冒号,而集合的前面结果就是单纯的结果