Python之路——迭代器与生成器
一、迭代器
1 # -*- encoding:utf-8 -*- 2 3 4 # dir([1,2].__iter__())是列表迭代器中实现的所有方法,dir([1,2])是列表中实现的所有方法 5 # print(dir([1,2].__iter__())) 6 # print(dir([1,2])) 7 # print(set(dir([1,2].__iter__()))-set(dir([1,2]))) # {'__length_hint__', '__setstate__', '__next__'} 8 9 # iter = [1,2,3,4,5,6].__iter__() 10 # print(iter.__length_hint__()) 11 # print(iter.__next__()) 12 # print(iter.__next__()) 13 # print(iter.__length_hint__()) # 获取迭代器中剩余元素的长度 14 # 15 # print('**',iter.__setstate__(0)) # 根据索引值指定从哪里开始迭代 16 # print(iter.__next__()) 17 # print(iter.__next__()) # 一个一个的取值 18 # print(iter.__next__()) 19 # print(iter.__next__()) 20 21 # l = [1,2,3,5] 22 # l_iter = l.__iter__() 23 # item = l_iter.__next__() 24 # print(item) 25 # item = l_iter.__next__() 26 # print(item) 27 # item = l_iter.__next__() 28 # print(item) 29 # item = l_iter.__next__() 30 # print(item) 31 # item = l_iter.__next__() # 如果迭代器里已经没有元素了,会抛出一个StopIteration异常 32 # print(item) 33 34 # l = [1,2,3,4] 35 # l2 = l.__iter__() 36 # while True: 37 # try: 38 # item = l2.__next__() 39 # print(item) 40 # except StopIteration: 41 # print('迭代完毕') 42 # break 43 44 # 迭代器遵循迭代器协议:必须拥有__iter__方法和__next__方法 45 46 # range() 47 # print('__next__' in dir(range(12))) # False 48 # print('__iter__' in dir(range(12))) # True 49 50 # from collections import Iterator 51 # print(isinstance(range(12),Iterator)) # False , 验证range执行之后得到的结果不是一个迭代器 52 53 # 为何要有for循环 54 55 # l = [1,2,3] 56 # index = 0 57 # while index < len(l): 58 # print(l[index]) 59 # index += 1 60 61 # 序列类型字符串,列表,元组都有下标,用上述方式访问,perfect! 62 # 但是对于字典、集合、文件对象这种非序列型类型,就得使用for循环了。 63 # for循环就是基于迭代器协议提供了一个统一的可以遍历所有对象的方法, 64 # 即在遍历之前,先调用对象的__iter__方法将其转换成一个迭代器, 65 # 然后使用迭代器去循环访问 66 67 # 迭代器的好处是可以节省内存 68 69 # print('__iter__' in dir(int)) # False 70 # print('__iter__' in dir(bool)) # False 71 # print('__iter__' in dir(list)) # True 72 # print('__iter__' in dir(dict)) # True 73 # print('__iter__' in dir(set)) # True 74 # print('__iter__' in dir(tuple)) # True 75 # print('__iter__' in dir(enumerate([]))) # True 76 # print('__iter__' in dir(range(2))) # True 77 # print('__next__' in dir(range(2))) # False 78 # print('__next__' in dir(dict)) # False 79 80 # g = range(10).__iter__() 81 # print(g.__next__()) 82 # print(g.__next__()) 83 # print(g.__next__()) 84 # print(g.__next__()) 85 # print(g.__next__()) 86 # print(g.__next__()) 87 from collections import Iterator 88 from collections import Iterable 89 90 # class A: 91 # def __iter__(self): pass 92 # def __next__(self): pass 93 # 94 # a = A() 95 # print(isinstance(a,Iterator)) # True 96 # print(isinstance(a,Iterable)) # True 97 98 # class A: 99 # def __iter__(self): pass 100 # #def __next__(self): pass 101 # 102 # a = A() 103 # print(isinstance(a,Iterator)) # False 104 # print(isinstance(a,Iterable)) # True 含有__iter__方法,是可迭代的,可迭代的,不一定是迭代器 105 106 # class A: 107 # # def __iter__(self): pass 108 # def __next__(self): pass 109 # 110 # a = A() 111 # print(isinstance(a,Iterator)) # False 112 # print(isinstance(a,Iterable)) # False 不含有__iter__方法,是不可迭代的 113 114 # 可以被for循环的都是可迭代的 115 # 可迭代的内部都有__iter__方法 116 # 只要是迭代器,一定可迭代 117 # print(range(10).__iter__()) 118 119 # for 120 # 只有可迭代对象才能用for 121 # b = [].__iter__() 122 # a = b.__iter__() 123 # c = [].__iter__().__iter__() 124 # print(b) 125 # print(a) 126 # print(c)
二、生成器
# -*- encoding:utf-8 -*- # 在某些情况下,我们想要像迭代器那样节省内存,就只能自己写。 # 我们自己写的这个能实现迭代器功能的东西就叫生成器 # Python中提供的生成器: # 1.生成器函数:常规函数定义,但是使用yield语句返回结果,而不是return语句。 # yield语句一次返回一个结果,在那个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行 # 2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表 # yield 和return不能共用 # 初识生成器 # import time # def generator_fun1(): # a = 1 # print('现在定义了a变量') # yield a # b = 2 # print('现在定义了b变量') # yield b # # g1 = generator_fun1() # generator_fun1() 返回一个可迭代的对象 # print('g1: ',g1) # g1: <generator object generator_fun1 at 0x00000250C7EBE4C0> # # print(next(g1)) # time.sleep(1) # print(next(g1)) # 输出: # 现在定义了a变量 # 1 # 现在定义了b变量 # 2 # 生成器好处:不会一下子在内存中生成太多数据 # 初识生成器二 # def produce(): # '''生成衣服''' # for i in range(1,200): # yield '生成了第%s件衣服'%i # # product_g = produce() # print(product_g.__next__()) # print(product_g.__next__()) # print(product_g.__next__()) # num = 0 # for i in product_g: # print(i) # num += 1 # if num == 5: # break # 生成器监听文件输入???????????????????? # import time # def tail(filename): # f = open(filename,encoding='utf-8') # f.seek(0,2) # 从文件末尾算起 # while 1: # line = f.readline() # 读取文件中新的文本行 # if not line.strip(): # time.sleep(0.1) # continue # yield line.strip() # tail_g = tail('tmp') # for line in tail_g: # print(line) # import time # def tail(filename): # f = open(filename,encoding='utf-8') # f.seek(0,2) # while 1: # line = f.readline().strip() # if not line: # time.sleep(0.1) # continue # yield line # tail_g = tail('tmp') # for line in tail_g: # print(line) # 计算移动平均值 # def averager(): # total = 0.0 # count = 0 # average = None # while True: # term = yield average # total += term # count += 1 # average = total/count # # g_avg = averager() # next(g_avg) # print(g_avg.send(10))# 先send一个值,再执行next函数 # print(g_avg.send(30)) # print(g_avg.send(50)) # 计算移动平均值二 # def init(func): # def inner(*args,**kwargs): # g = func(*args,**kwargs) # next(g) # return g # return inner # @init # def averager(): # total = 0.0 # count = 0 # average = None # while True: # term = yield average # total += term # count += 1 # average = total/count # # # g_avg = averager() # # print(g_avg.send(10)) # print(g_avg.send(30)) # print(g_avg.send(50)) # yield from # def gen1(): # for c in "AB": # yield c # for i in range(3): # yield i # print(list(gen1())) # ['A', 'B', 0, 1, 2] # # def gen2(): # yield from 'AB' # yield from range(3) # print(list(gen2())) # ['A', 'B', 0, 1, 2] #列表推导式和生成器表达式 # egg_list = ['鸡蛋%s' %i for i in range(10)] # 列表解析 # print(egg_list) # # laomuji = ('鸡蛋%s' %i for i in range(10)) # 生成器表达式 # print(laomuji) # print(next(laomuji)) # next()本质就是调用__next__ # print(laomuji.__next__()) # print(next(laomuji)) #总结 # 1.把列表解析的[]换成()得到的就是生成器表达式 # 2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存 # 3.Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议 # 访问对象的。例如,sun函数是python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器的协议, # 所以,我们可以直接这样计算一系列值的和: # print(sum(x ** 2 for x in range(4)))
三、生成器进阶练习
1 # -*- encoding:utf-8 -*- 2 # def generator(): 3 # print(123) 4 # content = yield 1 5 # print('=====',content) 6 # print(456) 7 # arg = yield 2 8 # print(arg) 9 # yield 10 11 # g1 = generator() 12 # g2 = generator() 13 # g1.__next__() 14 # g2.__next__() 15 # print('***',generator().__next__()) 16 # print('***',generator().__next__()) 17 18 # g = generator() 19 # ret = g.__next__() 20 # print(ret) 21 # ret = g.send('hello') 22 # print(ret) 23 # print(g.send(1234)) 24 25 # send 获取下一个值的效果和next基本一致 26 # 只是在获取下一个值的时候,给上一个yield的位置传递一个数据 27 #使用send的注意事项 28 # 第一次使用生成器的时候,是用next获取下一个值 29 # 最后一个yield不能接受外部的值 30 31 # def init(func): 32 # def inner(*args,**kwargs): 33 # g = func(*args,**kwargs) 34 # g.__next__() 35 # return g 36 # return inner 37 # @init 38 # def averager(): 39 # sum = 0.0 40 # count = 0 41 # average = 0 42 # while 1: 43 # temp = yield average 44 # sum += temp 45 # count += 1 46 # average = sum/count 47 # g = averager() 48 # print(g.send(10)) 49 # print(g.send(30)) 50 # print(g.send(5)) 51 52 #yield from 53 # def gnrator(): 54 # a = 'AB' 55 # for i in a: 56 # yield i 57 # b = [1,2,3] 58 # for i in b: 59 # yield i 60 # g = gnrator() 61 # for i in g: 62 # print(i) 63 64 # def gnrator2(): 65 # yield from 'AB' 66 # yield from [1,2,3] 67 # g = gnrator2() 68 # for i in g: 69 # print(i) 70 71 # 列表推导式 72 # egg_list = ['egg%s' %i for i in range(10)] 73 # print(egg_list) 74 # print([i*i for i in range(1,10)]) 75 76 # 生成器表达式 77 # g = (i for i in range(10)) #几乎不占用内存 78 # print(g) 79 # for i in g: 80 # print(i) 81 82 # g2 = (i for i in range(20) if i%2 == 1) 83 # for i in g2: 84 # print(i) 85 86 # g3 = (i*i for i in range(10)) 87 # for i in range(10): 88 # print(g3.__next__()) 89 90 #各种推导式练习 91 # names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], 92 # ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] 93 # ret = [name for lst in names for name in lst if name.count('e') == 2] 94 # print(ret) 95 # 字典推导式 96 # mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3} 97 # mcase2 = {k.lower(): mcase.get(k.lower(),0)+mcase.get(k.upper(),0) for k in mcase} 98 # print(mcase2) 99 # 集合推导式 100 # sq = {x**2 for x in [1,-1,2]} 101 # print(sq)