1.迭代器回顾
可迭代对象:Iterable 可以直接作用于for循环的对象统称为可迭代对象:Iterable。因为可迭代对象里面存在可迭代协议,所以才会被迭代 可迭代对象包括: 列表(list) 元组(tuple) 字典(dict) 集合(set) 字符串(str) 生成器(generator) 也可以说除了int和bool类型的数据以外,都是可迭代对象。 为什么他们能被迭代? 因为他们还有__iter__方法 可以使用 isinstance() 判断一个对象是否是 Iterable 对象。 迭代器:Iterator 它表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可 以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的, 只有在需要返回下一个数据时它才会计算。Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。 迭代器包括: 生成器(generator)都是 Iterator 对象 但 list 、 dict 、 str 虽然是 Iterable ,却不是 Iterator 。 如何把可迭代对象变成迭代器? python2 把 list 、 dict 、 str 等 Iterable 变成 Iterator 可以使用 iter() 函数 isinstance(iter('abc'), Iterator) python3 把 list 、 dict 、 str 等 Iterable 变成 Iterator 可以使用__ iter__() 函数 from collections import Iterable str ="abc" print(isinstance(str.__iter__(),Iterable))
2.生成器 generator
装饰器的本质是闭包 生成器的本质是迭代器 python中的generator保存的是算法,真正需要计算出值的时候才会去往下计算出值。它是一种惰性计算(lazy evaluation)。 在python中有三种方式来获取生成器(python中提供的生成器) 1.通过生成器函数 2.通过各种推到式来实现生成器 3.通过数据的转换也可以获取生成器(目前还不会) 1.通过生成器函数
def func(): print(1) yield 5 # 我的函数走到这了 print(2) yield 9 # 我的函数走到这了 g = func() # 生成一个生成器
print(g.__next__()) 1.在函数中使用yield关键字,函数就变成了一个generator。(看到有yiled的存在就是生成器函数) 其中的yiled可以和普通函数中的return进行比较: 普通函数碰到return就结束函数 生成器函数碰到yield不结束就挂起,进行分段执行。在执行到yiled的时候,函数会记住本次执行到的位置,当下一次调用时,就从该位置开始。 yiled特点: 1.挂起函数 2.返回值给调用者 3.接受值,可以接受调用者传参 2.如果我们循环和传参的话,需要使用的send()函数。 send函数的作用和__next__函数一样,都是让生成器执行到下一个yiled 区别: send可以给上一个yield的位置传递值,不能给最后一个yield发送值,在第一次执行生成器的时候最好不要使用send(),如果非要使用的话,需要给个传递个空值。send(None) send()函数的本质是next+参数 3.生成调用方法 1.__next__方法 2.生成器调用方法 3.send方法(本质是next+参数) 4.生成器优点 在了解迭代器的时候我们知道,迭代器是通过python语言本身实现的迭代功能,来节省内存地址的 起始生成器也是一样,只是为了在某些情况下,我们也需要节省内存,就只能自己写。我们自己写的这个能实现迭代器功能的东西就叫生成器。 5.在python3中提供一种可以直接把可迭代对象中的每一个数据作为生成器的结果进行返回 def func(): lst = ['卫龙','老冰棍','北冰洋','牛羊配'] yield from lst 相当于for item in lst: g = func() for i in g: print(i) --->
2.通过推导式(把一个列表生成式的[]
改成()
,就创建了一个generator)
g = (i for i in range(10)) print(g) ---> <generator object <genexpr> at 0x0000000002143D00>
3.生成器总结
1.生成器的本质就是一个迭代器 2.生成器一定是一个迭代器,迭代器不一定是一个生成器 3.生成器是可以让程序员自己定义的一个迭代器 4.生成器的好处,节省内存空间 5.生成器的特性 一次性的,惰性机制,从上向下 6.send相当于 next+传值,第一次触生成器的时候,如果使用send(None),值必须是None,一般我建议你们使用__next__ 7.python2 iter() next() python3 iter() next() __next__() __iter__() 8.yield from 将可迭代对象元素逐个返回
3.推导式
推导式的用法 【结果 语法】 容器 就是将【】替换成想要推导的数据类型的符号 (第一个位置是结果,剩下的都是语句) 推导式: 1.列表推导式 print([item for item in range(10)]) 2.集合推导式 print({item for item in range(10)}) 3.字典推导式 print({item:item+1 for item in range(10)}) 4.生成器推导式:(最简单的办法是将列表推导式的[]换成())
print(i for i in range(10))--->打印出来的是生成器的内存地址,__next__才会调用 #根据推导式写出小于100的奇数 print([item for item in range(100) if item %2 !=0 ]) 注意: 推导式不宜写太长,可读性差 实现小的需求时,可以使用推导式,节省代码