您好!此笔记的文本和代码以网盘形式分享于文末!
因个人能力有限,错误处欢迎大家交流和指正!基础部分内容简单,但多且零散!
Python迭代器和生成器 | ||
迭代:可以将某个数据集内的数据“一个挨着一个的取出来”,就叫做迭代。 | ||
可迭代数据类型:字符串、列表、元组、字典、集合 | ||
可迭代协议:可迭代协议的定义非常简单,就是内部实现了__iter__方法 | ||
迭代器:迭代器是一个可以记住遍历的位置的对象,迭代器遵循迭代器协议:必须拥有__iter__方法和__next__方法。节省内存 | ||
生成器:自己实现迭代器的功能代码叫生成器,在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。 | ||
生成器的本质:就是迭代器,特点是惰性运算,开发者自定义; | ||
生成器函数:一个包含yield关键字的函数就是一个生成器函数; | ||
生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表 | ||
生成器优点:延迟计算,一个返回一个结果,不会一次性生成所有结果,对于大数据处理很有意义。并且提高代码的可读性 | ||
用法 | 栗子 | 结果 |
迭代 | # 将数据集内的元素一个接一个取出来的过程叫做迭代 for i in [1, 2, 3, 'a']: print(i) | 1 2 3 a |
可迭代的数据类型 | # 字符串、列表、元组、字典、集合都是可迭代的 from collections import Iterable s1 = '12ab' li1 = [1, 2, 'a', 'b'] tu1 = (1, 2, 'a', 'c', ) di1 = {'a': 1, 'b': 2, } se1 = {1, 2, 3, 4} a = 123456789 print(isinstance(s1, Iterable)) print(isinstance(li1, Iterable)) print(isinstance(tu1, Iterable)) print(isinstance(di1, Iterable)) print(isinstance(se1, Iterable)) print(isinstance(a, Iterable)) | True True True True True False |
可迭代协议: 内部实现了__iter__方法 | # 对比可迭代数据类型中都有实现__iter__方法 print(dir(s1)) print(dir(tu1)) print(dir(a)) | |
不同数据类型 中__iter__方法的包含 字典和集合的无序特性 其无__setstate__方法 | print(set(dir(s1.__iter__())) - set(dir(s1))) print(set(dir(li1.__iter__())) - set(dir(li1))) print(set(dir(tu1.__iter__())) - set(dir(tu1))) print(set(dir(di1.__iter__())) - set(dir(di1))) print(set(dir(se1.__iter__())) - set(dir(se1))) | {'__next__', '__length_hint__', '__setstate__'} {'__next__', '__length_hint__', '__setstate__'} {'__next__', '__length_hint__', '__setstate__'} {'__next__', '__length_hint__'} {'__next__', '__length_hint__'} |
三个方法的使用和介绍 | iter_1 = li1.__iter__() # 获取迭代器中元素的长度 print(iter_1.__length_hint__()) # 根据索引值指定位置开始迭代 print(iter_1.__setstate__(2)) # 一个接一个的取值 print(iter_1.__next__()) print(iter_1.__next__()) | 4 None a b |
__next__方法 及其异常处理 | # __next__() 方法会由于无元素可取报异常 # 使用异常处理机制来处理掉异常 iter_1 = li1.__iter__() while True: try: item = iter_1.__next__() print(item) except StopIteration: break | 1 2 a b |
range() 是可迭代对象 但不是迭代器 | from collections import Iterator # range()关于iter和next方法测试 # 在range()执行后的内部是否有next和iter方法 print('__next__' in dir(range(12))) print('__iter__' in dir(range(12))) # 是否可迭代 print(isinstance(range(12), Iterable)) # 是否是迭代器 print(isinstance(range(12), Iterator)) | False True True False |
生成器函数 | # 生成器函数 import time def genrator_func(): a = 1 print('定义a 变量') yield a # 暂停,等待下次next()方法的执行 b = 2 print('定义b变量') yield b c = 3 print('定义c变量') yield c gen1 = genrator_func() print('g1: ', gen1) print('-'*17) print(next(gen1)) time.sleep(1) print(next(gen1)) | g1: <generator object genrator_func at 0x000001BB7B30F990> ----------------- 定义a 变量 1 定义b变量 2 |
生成器函数二 | def produce(): """ 生产定制手模 月生产力最多13个 """ for i in range(13): yield '生产了第%d个手模' % i produce_g = produce() # 接受客户定制订单 print('请输入订单数量:') num = int(input()) if num > 10: print('抱歉超过本月生产力,请返回重新输入!') j = 0 for i in produce_g: if j < num <= 10: print(i) j += 1 else: break # 样品生产 print('样品展示:', '\n', produce_g.__next__()) print(next(produce_g)) | 请输入订单数量: 11 抱歉超过本月生产力,请返回重新输入! 样品展示: 生产了第1个手模 生产了第2个手模 |
生成器监听文件输入列子 | ||
.send应用 时间间隔可更清晰的 看到运行顺序 | import time def generator(): print('开始') content = yield '返回1' print('第一个yield的值:', content) print('Two') content2 = yield '返回2' print('第二个yield的值:', content2) print('Three') content3 = yield "返回3" print('第三个yield的值:', content3) print('four') yield '第4次返回' g = generator() # 第一次运行只能使用next或send(None) print(g.send(None)) print('\n') time.sleep(6) # send 作用相当于next方法并将传递参数为 yield的返回值 print(g.send('第2次传入参数')) print('\n') time.sleep(6) # next方法 相当于 send(None) 即 temp = None print(g.__next__()) print('\n') time.sleep(6) # 最后一个yield不能接受外部的值 print(g.send(None)) | 开始 返回1 第一个yield的值: 第2次传入参数 Two 返回2 第二个yield的值: None Three 返回3 第三个yield的值: None four 第4次返回 |
计算移动平均值 | import time def averager(): total = 0.0 count = 0 average = None while True: print("第%d次执行" % count) term = yield average total += term count += 1 average = total / count print('第%d次接收的term值为:' % count) print(term) g_avg = averager() print('第一次调用send') print('第一次生成器yield返回值为', next(g_avg)) print('\n') time.sleep(6) print('第二次调用send') print('第二次生成器yield返回值为', g_avg.send(15)) print('\n') time.sleep(6) print('第三次调用send') print('第三次生成器yield返回值为', g_avg.send(30)) print('\n') time.sleep(6) print('第四次调用send') print('第四次生成器yield返回值为', g_avg.send(10)) | 第一次调用send 第0次执行 第一次生成器yield返回值为 None 第二次调用send 第1次接收的term值为: 15 第1次执行 第二次生成器yield返回值为 15.0 第三次调用send 第2次接收的term值为: 30 第2次执行 第三次生成器yield返回值为 22.5 第四次调用send 第3次接收的term值为: 10 第3次执行 第四次生成器yield返回值为 18.333333333333332 |
计算移动平均值 预激协程 | 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: print("第%d次执行" % count) term = yield average total += term count += 1 average = total / count print('第%d次接收的term值为:' % count) print(term) g_avg = averager() print('\n', '开始') print('第一次调用send') print('第一次生成器yield返回值为', g_avg.send(15)) print('\n') print('第二次调用send') print('第二次生成器yield返回值为', g_avg.send(30)) print('\n') print('第三次调用send') print('第三次生成器yield返回值为', g_avg.send(10)) | 第0次执行 开始 第一次调用send 第1次接收的term值为: 15 第1次执行 第一次生成器yield返回值为 15.0 第二次调用send 第2次接收的term值为: 30 第2次执行 第二次生成器yield返回值为 22.5 第三次调用send 第3次接收的term值为: 10 第3次执行 第三次生成器yield返回值为 18.333333333333332 |
yield from | def gen1(): for c in 'AB': yield c for i in range(3): yield i print(list(gen1())) def gen2(): yield from 'AB' yield from range(3) print(list(gen2())) | ['A', 'B', 0, 1, 2] ['A', 'B', 0, 1, 2] |
列表推导式1 | # 30以内所有能被3整除的数 multiples = [i for i in range(30) if i % 3 is 0] print(multiples) | [0, 3, 6, 9, 12, 15, 18, 21, 24, 27] |
生成器表达式1 | # 生成器表达式 multiples1 = (i for i in range(30) if i % 3 is 0) print(multiples1) print(next(multiples1)) print(multiples1.__next__()) print(next(multiples1)) | <generator object <genexpr> at 0x0000011DA10FF8E0> 0 3 6 |
列表推导式2 又称列表解析 缺点:内存占用大 机器容易卡死 | multiples = [i for i in range(30) if i % 3 is 0] def squared(x): return x ** 2 # 30以内所有能被3整除的数的平方 multiples2 = [squared(i) for i in range(30) if i % 3 is 0] print(multiples2) | [0, 9, 36, 81, 144, 225, 324, 441, 576, 729] |
生成器表达式2 优点:几乎不占内存 | multiples3 = (squared(i) for i in range(30) if i % 3 is 0) print(multiples3) print(next(multiples3)) print(multiples3.__next__()) print(next(multiples3)) | <generator object <genexpr> at 0x000002388D6BF990> 0 9 36 |
列表推导式3 | # 嵌套列表中查询 两个‘e’的所有名字 names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] eenames = [name for lst in names for name in lst if name.count('e') >= 2] print(eenames) | ['Jefferson', 'Wesley', 'Steven', 'Jennifer'] |
生成器表达式3 | eenames1 = (name for lst in names for name in lst if name.count('e') >= 2) print(eenames1) print(next(eenames1)) print(eenames1.__next__()) print(next(eenames1)) | <generator object <genexpr> at 0x0000024A95F9F9E8> Jefferson Wesley Steven |
python内置函数sum | # 使用迭代器协议访问对象的函数sum ret1 = sum(x ** 2 for x in range(4)) print(ret1) | 14 |
字典推导式1 | # 将字典的Key和Value对调 dic1 = {'a': 1, 'b': 2, } dic1_frequency = {dic1[k]: k for k in dic1} print(dic1_frequency) | {1: 'a', 2: 'b'} |
字典推导式2 | # 合并大小写对应的 value值,将K统一成小写 dic2 = {'a': 1, 'b': 2, 'A': 7, 'D': 6, } print(list(k for k in dic2.keys())) print(list(l1.lower() for k in dic2.keys() for l1 in k)) print(list(dic2.get(l1.lower()) for k in dic2.keys() for l1 in k)) print(list(dic2.get(l1.lower(), 0) for k in dic2.keys() for l1 in k)) print(list(l1.upper() for k in dic2.keys() for l1 in k)) print(list(dic2.get(l1.upper()) for k in dic2.keys() for l1 in k)) print(list(dic2.get(l1.upper(), 0) for k in dic2.keys() for l1 in k)) dic2_sortout = {k.lower(): dic2.get(k.lower(), 0) + dic2.get(k.upper(), 0) for k in dic2.keys()} print(dic2_sortout) | ['a', 'b', 'A', 'D'] ['a', 'b', 'a', 'd'] [1, 2, 1, None] [1, 2, 1, 0] ['A', 'B', 'A', 'D'] [7, None, 7, 6] [7, 0, 7, 6] {'a': 8, 'b': 2, 'd': 6} |
集合推导式 | # 计算列表中每个值的平方且自带去重 squared = {x ** 2 for x in [1, -2, -1, 3]} print(squared) | {1, 4, 9} |
拓展1 | 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(g1)) print(list(g2)) print('\n') g3 = demo() g4 = (i for i in g3) g5 = (i for i in g4) print(list(g5)) print(list(g4)) print('\n') g6 = demo() g7 = (i for i in g6) g8 = (i for i in list(g7)) print(list(g8)) print('\n') g9 = demo() g10 = (i for i in g9) g11 = (i for i in list(g10)) print(list(g11)) print(list(g10)) print('\n') g12 = demo() g13 = (i for i in g12) print(list(g13)) g14 = (i for i in list(g13)) print(list(g11)) print('\n') | [0, 1, 2, 3] [] [0, 1, 2, 3] [] [0, 1, 2, 3] [0, 1, 2, 3] [] [0, 1, 2, 3] [] |
拓展2 | def add(n, i): return n+i def test(): for i in range(4): yield i g = test() for n in [1, 10]: g = (add(n, i) for i in g) print(list(g)) | [20, 21, 22, 23] |
拓展2 | def add(n, i): return n+i def test(): for i in range(4): yield i print('g:') g = test() for n in [1, 10]: g = (add(n, i) for i in g) print(list(g)) print('g1:') g1 = test() for n in [10, 1]: g1 = (add(n, i) for i in g1) print(list(g1)) print('g12:') g10 = test() for n in [1, ]: g11 = (add(n, i) for i in g10) for n in [10, ]: g12 = (add(n, i) for i in g11) print(list(g12)) | g: [20, 21, 22, 23] g1: [2, 3, 4, 5] g12: [20, 21, 22, 23] |
愿有更多的朋友,在网页笔记结构上分享更逻辑和易读的形式:
链接:暂无
提取码:暂无