迭代器
首先说几个概念:
- 什么是可迭代对象(iterable) : 顾名思义,可以返回一个迭代器的对象,也可以说能够在for循环中所使用的对象.如tuple,list,set等
- 什么是迭代器(iterator) : 从一个集合序列中不断提取元素,直到没有元素可以返回,抛出异常.
如何获取迭代器:
通过可迭代对象的 __iter__方法来获取,
1 #coding = utf-8 2 lst = ["小明",["小李"],"小王","小刘"] #lst是list类型,是可迭代对象 3 it = lst.__iter__() #it就是迭代器
如何判断是否为可迭代对象.
#coding = utf-8
content = dir(list)
print(content) #list中存在__iter__,是可迭代对象
'''
['__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) 通过dir()查看,同时存在__iter__和__next__方法的就是迭代器,只存在__iter__的就是可迭代对象.
print("__iter__"in dir(list))
print ("__next__"in dir(list)) #返回的是布尔值
(2)通过python的collections
from collections import iterable
from collections import iterator
print (isinstance(lst,iterable))
print (isinstance(lst,iterator))
print (isinstance(lt,iterable))
print (isinstance(lt,iterator))
迭代器的工作原理
通过调用__next__函数,返回序列中下一个元素,直到取到最后一个抛出异常.StopIteration.
#coding = utf-8
lst = ["小明","小李","小王","小刘"]
it = lst.__iter__()
while 1:
print(it.__next__()) #StopIteration
迭代器的特点
(1)只能返回下一个,不可逆向.
(2)惰性机制,只有给予指令之后才会执行操作.
(3)不占用内存.
通过__next__方法模拟for循环.
lst = ["小明","小李","小王","小刘"]
it = lst.__iter__()
while 1:
try:
print(it.__next__())
except StopIteration: #抛出异常退出
break
生成器
生成器和迭代器是较为容易混淆的两个概念.
生成器: 返回的是一个迭代器对象的就是生成器 , 简单来说,加上yield的函数便构成了一个生成器.
生成器的构造有以下几种方式:
1,通过yield,普通的函数中包含yield就是生成器.
2,通过生成器表达式
#coding = utf-8 #通过添加yield def func(): yield 2 gen = func() print(gen.__next__()) #2
#coding = utf-8 #通过推导式 gen = (i for i in range(0,3)) print(gen.__next__()) #0 print(gen.__next__()) #1 print(gen.__next__()) #2
在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 __next__() 时从当前位置继续运行。
实际上next()和send()在一定意义上作用是相似的,区别是send()可以传递yield表达式的值进去,而next()不能传递特定的值,只能传递None进去。因此,我们可以看做c.next() 和 c.send(None) 作用是一样的。
例如
#codiing = utf-8 def func(): yield 456 a = func() #获取迭代器对象 print (a.__next__()) #456 a = func() #惰性机制 print(a.send(none)) #456
显而易见,两次打印结果相等.
关于yield
yield的作用和return相似,都具有有类似break特点,不同点是其中return是终止程序,而yield是等待下一次运行,分段进行函数.
#coding = utf-8 def func(): return 1 #第一个return返回,第二个被终止 不再执行 return 2 ret = func() print(ret)
#coding = utf-8 #1,2两个值都被返回 # def func(): # yield 1 # yield 2 # gen = func() # print(gen.__next__()) #1 # print(gen.__next__()) #2
关于send()
send()和__next__一样,都具有让生成器走向下一次的作用,但是send()具有向上一个yield传递值的作用,也正是由于这一特性,第一次执行生成器代码的时候,用__next__而不用send()
#coding =utf-8 def func(): a = yield 1 yield a yield 3 gen = func() print(gen.__next__()) print(gen.send(5)) #send里的值赋值给上一个yield 导致a = 5 print(gen.send(gen))