python全栈闯关--14-生成器进阶
1、复习
def generator(): print('1') yield 'a' print('2') yield 'b' print('3') g = generator() res = g.__next__() # 第一个__next__执行到第一个yiled停止, 并返回第一个yiled处的值 print(res) res = g.__next__() # 第二个__next__执行到第二个yiled停止, 并返回第二个yiled处的值 print(res) res = g.__next__() # 虽然执行了print('3')操作,但是报错,因为后续没有yiled了,为了避免报错,可以结尾加上yiled print(res)
2、send
def generator(): print('1') num = yield 'a' # 此处如果继续执行,使用__next__触发,num将会被复制None。使用send,num将会接收seed的值 print("seed num:%s" % num) print('2') yield num * 2 print('3') yield g = generator() res = g.__next__() # 第一个__next__执行到第一个yiled停止, 并返回第一个yiled处的值 print(res) res = g.send(10) # 发送值给生成器内部,并返回下一个yiled处的值 print(res) res = g.__next__() # 虽然执行了print('3')操作,但是报错,因为后续没有yiled了,为了避免报错,可以结尾加上yiled print(res) # 由于yield没有返回值,返回None
- send的获取下一个值得能力和next一致。
- send时,传递值给当前send位置的yield,并执行代码带一个yiled处停止
- 使用send注意事项:
- 第一次获取生成器的值时,使用next,不能以开始就是用send
- 最后一个yiled的位置,不能使用send,否则会报错“StopIteration”
3、yield from
yiled from 可以从生成器函数中,依次返回各个值
def func(): s = 'abcd' num = '1234' yield from s yield from num for i in func(): print(i)
4、生成器表达式
生成器表达式:在一行代码中,完成生成器
结构: (元素 for 元素 in 元素范围)
生成器表达式:
g = (i for i in range(10)) for i in g: print(i)
不调用不返回值,几乎不暂用内存
如果把括号改成方括号,则是列表推导式
g = [i for i in range(10)] print(g) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
区别是列表推导式执行完毕时,列表就生成了,已经分配内存
5、各种推导式
列表推导式
[每一个元素或者和元素相关的操作 for 元素 in 可迭代数据类型] #遍历之后挨个处理
[满足条件的元素相关操作 for 元素 in 可迭代数据类型 if 元素相关的操作] #筛选
# 30以内所有能被3整除的数 ret = [i for i in range(30) if i%3 == 0] print(ret) # 30以内所有能被3整除的数的平方 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)
字典推导式:
# 例一:将一个字典的key和value对调 mcase = {'a': 10, 'b': 34} dic = { mcase[k]:k for k in mcase} print(dic) # 例二:合并大小写对应的value值,将k统一成小写 mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3} dic = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase} print(dic)
集合推导式:
#集合推导式,自带结果去重功能 squared = {i*i for i in [1, -1, 2]} print(squared)
6、练习
# 获取移动平均值 def move_arg(): sum = 0 count =0 avg = 0 while 1: num = yield avg sum += num count += 1 avg = sum / count g = move_arg() print(g.__next__()) print(g.send(10)) print(g.send(20)) print(g.send(30)) print(g.send(10))
使用装饰器,完善上述代码,是代码,使代码运行更加顺畅
def init(f): def warp(): g = f() # 调用生成器函数,得到一个生成器 g.__next__() # 预激活,执行next return g # 返回激活器 return warp @init def move_arg(): sum = 0 count =0 avg = 0 while 1: num = yield avg sum += num count += 1 avg = sum / count g = move_arg()
# 3.处理文件,用户指定要查找的文件和内容,将文件中包含要查找内容的每一行都输出到屏幕 def check_file(file,find_str): with open(file,encoding ='utf-8') as f : for i in f: if find_str in i: yield i g = check_file("总结复习.py",'迭代器') for i in g: print(i, end='')
# 4.写生成器,从文件中读取内容,在每一次读取到的内容之前加上‘***’之后再返回给用户。 def get_line(file): with open(file,encoding ='utf-8') as f: for i in f: yield "***" + i g = get_line("总结复习.py") for i in g: print(i, end='')
7、总结和复习
- 迭代器和生成器
- 迭代器
- 可迭代协议: 含有__iter__方法的都是可迭代的
- 迭代器协议:含有__next__和__iter__方法的都是迭代器
- 特点:
- 节省内存
- 可以方便的遍历去到每一个值
- 生成器——本质是一个迭代器
- 生成器函数:
- 含有yield关键字的都是迭代器
- 生成器的特点:
- 调用函数之后函数内的代码不会执行,返回生成器
- 每次从生成器中取一个值,都会执行一段代码,到yiled就停止
- 如何从生成器中取值:
- for:如果没有break会一直取完
- next:一次只取一个值
- send:不能用在第一个和最后一个,取下一个值得时候,给上一个值得位置,传递一个新的值
- 数据类型强制转换:会一次性得到所有的值,暂用内存
- 生成器表达式:
- (符合条件的元素i for i in 可迭代 if 条件)