函数四--迭代器和生成器
一、迭代器
迭代器协议:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么引起一个StopIteration异常,以终止迭代(只能往后走,不能往前走)。
实现了迭代器协议的对象(对象内部定义了一个__iter__()方法)
python中的内部工具(如for循环,sum,min,max函数等)都是基于迭代器协议访问对象
只要含有__iter__方法的都是可迭代的-----可迭代协议;迭代器协议:内部含有__next__和__iter__方法的就是迭代器
只要是迭代器就一定可迭代; 可迭代的.__iter__()方法就可以得到一个迭代器; 迭代器中的__next__()方法可以一个一个的获取值。
当我们遇到一个新的变量,不确定能不能for循环的时候,就判断它是否可迭代,因为只有是可迭代对象的时候才能用for
迭代器的好处:
1:从容器类型中一个一个的取值,会把所有的值都取到
2:节省内存空间(range,文件句柄f)
迭代器并不会在内存中占用一大块内存,而是随着循环,每次生成一个,通过每次next会每次给我一个
li = [1,2,3] #基于迭代器协议 iterator = li.__iter__() print(iterator.__next__()) # 1 print(iterator.__next__()) # 2 print(iterator.__next__()) # 3 # print(iterator.__next__()) #超出边界报错 #下标 print(li[0]) # 1 print(li[1]) # 2 print(li[2]) # 3 print(li[3]) # 超出边界报错
#用while循环模拟for循环机制 li = [1,2,3] iterator = li.__iter__() while True: try: print(iterator.__next__()) except StopIteration: print('迭代完毕,循环终止') break # for循环访问方式 # for循环本质就是遵循迭代器协议的访问方式,先调用iterator = li.__iter__()方法, # 然后依次执行iterator.__next__(),直到捕捉到 StopItearation终止循环 # for循环所有的对象的本质都是一样的原理
二、生成器 ---本质就是迭代器
在调用生成器运行的过程中,每次遇到yield时函数会暂停并保存当前所有的运行信息,返回yield的值。并在下一次执行next()方法时从当前位置继续运行
表现形式
1、生成器函数 带yield的函数(a.返回值 b.保留函数的运行状态)
next(t) t.__next__() t.send()
#用生成器函数 #yield相当于return控制的是函数的返回值 #x=yield的另外一种特性,接收send传过来的值,赋值给x def test(): print("begin") first = yield # return 1 first = None print("111",first) yield 2 print("222") t = test() print(test().__next__()) res = t.__next__() # next(t) print(res) res = t.send("函数停留在first那个位置,我就是给first赋值的") print(res) ''' 输出结果: begin None begin None 111 函数停留在first那个位置,我就是给first赋值的 2 '''
2、生成器表达式
g = (i for i in range(10)) # print(g) for i in g: print(i)
各种推导式
# [每一个元素或者是和元素相关的操作 for 元素 in 可迭代数据类型] #有点像遍历之后挨个处理 # [满足条件的元素相关的操作 for 元素 in 可迭代数据类型 if 元素相关的条件] #筛选功能 ret = [i for i in range(30) if i % 3 == 0] print(ret) ret = [i * i for i in range(30) if i % 3 == 0] print(ret)
# 找到嵌套列表中名字含有两个‘e’的所有名字 names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] ret = [name for lst in names for name in lst if name.count('e') == 2] print(ret)
# dic = {'a':10,'b':34} # dic1 = {dic[k]:k for k in dic} # print(dic1) #各种推导式:生成器、列表、字典、集合 #遍历操作 #筛选操作 #生成器中的数据只能取一次,取完就没有了 #惰性运算,不找它取值,它就不工作
#生成器表达式和列表推导式的区别: #括号不一样 #返回的值不一样 :生成器几乎不占用内存