1.今日内容
- 生成器初识
- 生成器产生方式
- yield与return的区别
- yield与yield from的区别
- send与next的区别
- 列表推导式,生成器表达式(字典推导式,集合推导式)
- 闭包
2.具体内容
-
生成器初识
- 生成器本质就是迭代器,python社区中生成器与迭代器是一种概念。生成器与迭代器的唯一区别:迭代器都是python给你提供的已经写好的工具或者通过数据转化得来的,(比如文件句柄,iter([1,2,3]))。生成器是我们自己用python代码构建的工具
-
生成器产生方式
- 生成器函数
def func(): print(666) yield 2,4,6 print(888) yield 8 ret = func() #生成器对象 print(ret) # <generator object func at 0x0000000001E10F68> print(next(ret)) print(next(ret)) #只要函数中出现yield,那么他就不是函数,它是生成器函数 #一个next对应一个yield,next超过yield数量会报错,StopIteration
- 生成器表达式
ret = (i for i in range(3)) print(ret) #<generator object <genexpr> at 0x10307f0d0> #如何触发生成器(迭代器)取值 #1.next(obj) print(next(ret)) #2.for 循环 for i in range(3): print(next(ret)) #3.数据转化 print(list(obj))#[0,1,2]
- python给你提供的一些内置函数,返回一个生成器
l1 = [1,2,3] ret = iter(l1) print(next(ret))
-
yield与与return的区别
- return:结束函数,给函数的执行者返回值(多个值通过元组的形式返回)
- yield:不结束函数,对应着给next返回值(多个值通过元组的形式返回)
-
yield 与yield from
#yield from 的作用 def func(): yield from [1,2,3] ret = func() print(next(ret))#1 print(next(ret))#2 print(next(ret))#3 #yield:对应yield给next返回值 #yield from:将一个可迭代对象的每一个元素返回给next #yield from:节省代码,提升效率(代替for循环)
-
send与next区别
- 相同点
- send和next都可以让生成器对应的yield向下执行一次
- 都可以获取yield生成的值
- 不同点
- 第一次获取yield值只能用next,不能用send(可以send(None))
- send可以给上一个yield传递值
def func(name): print(f'{name} ready to eat') while 1: food = yield '骨头' print(f'{name} start to eat {food}') dog = func('将军') next(dog) #第一次必须用next让指针停留在第一个yield后面不能用shed(send(None)) #如 ret = dog.send(None) #与next一样,可以获取yield的值 #还可以给上一个yield发送值 ret = dog.send('香肠') print(ret)
- 相同点
-
列表推导式,生成器表达式(字典推导式,集合推导式)
- 列表推导式:一行代码构建一个有规律比较复杂的列表
# l1 = [] for i in range(5): l1.append(i) print(l1) #列表推导式 l1 = [i for i in range(1,11)] print(l1)
-
两种构建方式
- 循环模式:[变量(加工后的变量) for 变量 in iterable]
# 将10以内所有整数的平方写入列表。 print([i**2 for i in range(1,11)]) # 100以内所有的偶数写入列表. print([i for i in range(2,101,2)]) # 从包子1期到包子100期写入列表list print([f'包子{i}期' for i in range(1,101)])
- 筛选模式:[变量(加工后变量) for 变量 in iterable if 条件]
# 1-100里大于49的数 print([i for i in range(1,101) if i > 49]) # 三十以内可以被三整除的数 print([i for i in range(1,31) if i %3 == 0]) # 过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母 l1 = ['barry', 'fdsaf', 'alex', 'sb', 'ab'] print([i.upper() for i in l1 if len(i) > 3]) # 找到嵌套列表中名字含有两个‘e’的所有名字 names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] print(s for i in names for s in i if s.count('e') == 2)
-
列表推导式的优缺点
简单,快捷;但可读性不高,不好排错
-
字典推导式,集合推导式
# 字典推导式,集合推导式: 两种模式: 循环模式,筛选模式 l1 = ['小潘', '怼怼哥','西门大官人', '小泽ml亚'] # {0: '小潘', 1: '怼怼哥', 2: '西门大官人'} #字典推导式 print({i:l1[i] for i in range(len(l1))}) #集合推导式 print({i for i in range(10)})
-
闭包
- 什么是闭包
- 闭包只能存在嵌套函数中
- 内层函数对外层函数非全局变量的引用(使用),就会形成闭包
- 被引用的非全局变量也称自由变量,这个自由变量会与内层函数产生一个绑定关系
- 自由变量不会在内存中消失
- 闭包的作用
- 保证数据的安全
def func(): l1 = [] def inner(s): l1.append(s) total = sum(l1) return total/len(l1) return inner s = func() print(s(100)) print(s(120)) print(s(140)) #坑 def func(a,b): def inner(): print(a) print(b) return inner a = 2 b = 3 ret = func(a,b) #如何判断是闭包 print(ret.__code__.co_freevars)
- 什么是闭包