python基础15下_迭代器_生成器
print(dir([])) #告诉我列表拥有的所有方法 # 双下方法 # print([1].__add__([2])) print([1]+[2]) ret = set(dir([]))&set(dir({}))&set(dir(''))&set(dir(range(10))) print(ret) #iterable print('***'.center(50,'-')) # 只要是能被for循环的数据类型 就一定拥有__iter__方法 print('__iter__' in dir(int)) print('__iter__' in dir(bool)) print('__iter__' in dir(list)) print('__iter__' in dir(dict)) print('__iter__' in dir(set)) print('__iter__' in dir(tuple)) print('__iter__' in dir(enumerate([]))) print('__iter__' in dir(range(1))) # Iterable 可迭代的 -- > __iter__ # 只要含有__iter__方法的都是可迭代的 # [].__iter__() 迭代器 -- > __next__ # 通过next就可以从迭代器中一个一个的取值 # 只要含有__iter__方法的都是可迭代的 —— 可迭代协议 # 迭代器的概念 # 迭代器协议 —— 内部含有__next__和__iter__方法的就是迭代器 # 迭代器协议和可迭代协议 # 可以被for循环的都是可迭代的 # 可迭代的内部都有__iter__方法 # 只要是迭代器 一定可迭代 # 可迭代的.__iter__()方法就可以得到一个迭代器 # 迭代器中的__next__()方法可以一个一个的获取值 from collections import Iterable from collections import Iterator print('****'.center(50,'_')) print(isinstance([],Iterator)) # False 不是迭代器 print(isinstance([],Iterable)) # True 是可迭代的 #迭代器的好处: # 从容器类型中一个一个的取值,会把所有的值都取到。 # 节省内存空间 #迭代器并不会在内存中再占用一大块内存, # 而是随着循环 每次生成一个 # 每次next每次给我一个
# 生成器 —— 迭代器 # 生成器函数 —— 本质上就是我们自己写得函数 # 生成器表达式 #只要含有yield关键字的函数都是生成器函数 # yield不能和return共用且需要写在函数内 def generator(): print(1) yield 'a' # #生成器函数 : 执行之后会得到一个生成器作为返回值 ret = generator() # 拿到生成器 print(ret) # 打印内存地址 print(ret.__next__()) # 执行函数体,直到遇到 yield def generator2(): print(111) yield 'aaa' print(222) yield 'bbb' yield 'ccc' g = generator2() # for i in g: # print(i) ret = g.__next__() print(ret) ret = g.__next__() print(ret) ret = g.__next__() print(ret) #娃哈哈%i def wahaha(): for i in range(2000000): yield '娃哈哈%s'%i g = wahaha() g1 = wahaha() # 两个独立的生成器 print(g.__next__()) print(g.__next__()) print(g1.__next__()) print(g1.__next__()) gg = wahaha() count = 0 for i in gg: count +=1 print(i) if count > 50: break print('*******',gg.__next__()) # 生成器继续前面的往下走 for i in gg: # 生成器继续前面的往下走 count +=1 print(i) if count > 100: break
生成器与send方法
# 从生成器中取值的几个方法 # next # for # 数据类型的强制转换 : 缺点:占用内存 def generator(): print(123) content = yield 1 print('=======',content) print(456) arg = yield 2 '''''' yield g1 = generator() g2 = generator() g1.__next__() g2.__next__() print('>>>>>',generator().__next__()) print('***',generator().__next__()) g = generator() ret = g.__next__() print('***',ret) ret = g.send('hello') # send的效果和next一样, 但是多了传递数据的功能 print('***',ret) # send 获取下一个值的效果和next基本一致 # 只是在获取下一个值的时候,给上一yield的位置传递一个数据 # 使用send的注意事项 # 第一次使用生成器的时候 是用next获取下一个值 # 最后一个yield不能接受外部的值
def generator(): print(123) content = yield 1 print('=======', content) print(456) yield 2 '''''' yield g = generator() ret = g.__next__() print('+++', ret) res = g.send('hello') # send的效果和next一样 print('--->', res) # send 获取下一个值的效果和next基本一致 # 只是在获取下一个值的时候,给上一yield的位置传递一个数据 # 使用send的注意事项 # 第一次使用生成器的时候 是用next获取下一个值 # 最后一个yield不能接受外部的值 # 案例应用: 获取移动平均值 # 10 20 30 10 # 10 15 20 17.5 # avg = sum/count def avgs(): sum = 0 cnt = 0 avg = 0 while True: num = yield avg sum += num cnt += 1 avg = sum / cnt g = avgs() g.__next__() avg1 = g.send(10) avg1 = g.send(8) print(avg1) avg2 = g.send(6) print(avg2)
利用生成器来监视文件内容:
# 文件内容监视 def tail(filename): with open(filename,encoding='utf8') as f: while 1: line = f.readline() if line.strip(): # print(line) yield line.strip() g = tail('file') for i in g: if 'python' in i: print('***',i)
给生成器函数加上装饰器,省掉一步 __next__()
# 预激生成器的装饰器 def init(func): # 装饰器 def inner(*args, **kwargs): g = func(*args, **kwargs) # g = average() g.__next__() return g return inner @init def average(): sum = 0 count = 0 avg = 0 while True: num = yield avg sum += num # 10 count += 1 # 1 avg = sum / count avg_g = average() # ===> inner ret = avg_g.send(10) print(ret) ret = avg_g.send(20) print(ret)
直接 yield from
def gen(): a = 'abcdef' b = '12345' yield from a # 直接对容器类型生成器 yield from b g = gen() # for i in g: # print(i) print(g.__next__()) print(g.__next__()) print(g.__next__()) print(g.__next__())
两个生成器的小例子:
# 3.处理文件,用户指定要查找的文件和内容,将文件中包含要查找内容的每一行都输出到屏幕 def check_file(filename, txt): with open(filename, encoding='utf8') as f: for i in f: if txt in i: yield i g = check_file('a.txt', '正当防卫') for i in g: print(i.strip()) # 4.写生成器,从文件中读取内容,在每一次读取到的内容之前加上‘***’之后再返回给用户。 def read_file(filename): with open(filename, encoding='utf-8') as f: # 句柄 : handler,文件操作符,文件句柄 for i in f: yield '***' + i for i in read_file('a.txt'): print(i.strip())
生成器表达式遇到循环
def demo(): for i in range(4): yield i g = demo() g1 =(i for i in g) g2 =(i for i in g1) # 以上所有都没干活 # print(list(g)) # 如果这里list了,则下面两个都取不到值,因为已经空了。 print(list(g1)) # list 取走了所有 g1 的值 print(list(g2)) # g2 已经空了,没有值 #### 生成器表达式 循环 def add(n,i): return n+i def test(): for i in range(4): yield i g=test() for n in [1,10,5]: g=(add(n,i) for i in g) # 遇到上面的for循环生成器表达式,就把它拆开如下: # n = 1 # g=(add(n,i) for i in test()) # n = 10 # g=(add(n,i) for i in (add(n,i) for i in test())) # n = 5 # g=(add(n,i) for i in (add(n,i) for i in (add(n,i) for i in test()))) # 上面一句的结果 g=(15,16,17,18) print(list(g)) # [15,16,17,18]