迭代器,生成器
---恢复内容开始---
iterable 可迭代的
什么是可迭代的
内部含有__iter__方法的数据类型就是可迭代的---可迭代协议
#字符串,字典,元组,列表,集合都是可迭代的 #他们都可以使用for循环 print(dir([])) print(dir(())) print(dir("wfdsf")) #打印出来的方法中都含有__iter__ print(dir(123)) #打印出来的方法中不包含__iter__
什么是迭代器
内部含有__next__方法的可迭代对象就是迭代器
迭代器是可迭代的一部分
#迭代器你可以理解为一个容器,我们从这个容器当中一个接着一个的把值取出来的过程就是迭代的过程 ret = "adc".__iter__() #可迭代对象调用__iter__()就形成了一个迭代器 print(set(dir("abc".__iter__()))-set(dir"abc"))) #打印迭代器和可迭代对象内部方法的差集 {'__length_hint__', '__next__', '__setstate__'}#结果 #__next__方法能在迭代器中一个一个取值 #利用while循环来实现for循环的功能 l = [1,2,3,4] l_iter = l.__iter__() while True: try: #处理异常 item = l_iter.__next__() print(item) except StopIteration: break
如何判断一个变量是不是迭代器或者是可迭代的
方法一: print('__iter__' in dir([1,2,3,4]))#判断方法__iter__是否存在于变量的方法中,存在则是可迭代的 print('__next__' in dir([1,2,3,4]))]))#判断方法__next__是否存在于变量的方法中,不存在则不是迭代器 方法二: from collections import Iterable from collections import Iterator print(isinstance([1,2,3,4],Iterable))#判断是不是可迭代对象 str_iter = 'abc'.__iter__() print(isinstance(str_iter,Iterator))#判断是不是迭代器 print(isinstance('abc',Iterable))
迭代器的特点
惰性运算
从前到后一次取值,过程不可逆,不可重复
节省内存
生成器
生成器的本质就是迭代器
因此生成器具有迭代器的特点,但是生成器是我们自己写的代码
1生成器函数
一个包含yield关键字的函数就是一个生成器函数。
yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。
def genrator_fun1():这个函数就是一个生成器函数 yield 1 yield 2 x=genrator_fun1()#x 就是一个生成器 print(x.__next__())#每一次调用都会返回一个结果 print(type(x)) print(x.__next__()) #结果 1 <class 'generator'> 2
def cloth(): for i in range(1000000): yield '衣服%s'%i g = cloth()#g是个生成器 print(g.__next__())每次调用__next__方法都会获取一个值 #衣服0 for i in range(3): print(g.__next__()) #衣服1 #衣服2 #衣服3 for i in range(3): print(g.__next__()) #衣服4 #衣服5 #衣服6 #然而 print(cloth().__next__())每次执行函数都会从头开始 print(cloth().__next__()) print(cloth().__next__()) #结果是 #衣服0 #衣服0 #衣服0
#监听文件末尾追加的例子 def tail(): f = open('文件','r',encoding='utf-8')#打开文件 f.seek(0,2)把光标移至末尾 while True: line = f.readline()#读取内容 if line:#内容不为空 yield line#返回读取到的内容 import time time.sleep(0.1) g = tail() for i in g: print(i.strip())
send方法
#从哪一个yield开始接着执行,就把一个值传给了那个yield
#send不能用在第一个触发生成器
#生成器函数中有多少个yield就必须有多少个next+send
def func(): print('*'*10) a = yield 5 print('a : ',a) yield 10 g = func() num = g.__next__() print(num) num2 = g.send('alex')#send方法 print(num2) #—————————— ********** 5 a : alex 10
def init(func): #生成器的预激装饰器 def inner(*args,**kwargs): g = func(*args,**kwargs) #func = averager g.__next__()#先执行一次__next__() return g return inner @init def averager():#求平均值 total = 0.0 count = 0 average = None while True: term = yield average#返回average.send传值给term total += term count += 1 average = total/count g_avg = averager() print(g_avg.send(10))#10 print(g_avg.send(30))#20
#yield form def func(): a = 'AB' b = 'CD' yield from a# 相当于for i in a:yield i yield from b# 相当于for i in b:yield i # 'A','B','C','D' # 返回了4次 g = func() for i in g: print(i)
2生成器表达式
#列表推导式 y = [1,2,3,4,5,6,7,8] x = [1,4,9,16,25,36,49,64] #由列表y要得到一个列表x x = [i*i for i in y]#列表推导式 #生成器表达式 #把列表推导式的[]换成()就变成了生成器表达式。 l = ['鸡蛋%s'%i for i in range(10)] print(l)#列表表达式获得一个列表 #生成器表达式获得了一个生成器 laomuji = ('鸡蛋%s'%i for i in range(10)) for egg in laomuji: print(egg)

浙公网安备 33010602011771号