闭包, 迭代器, 生成器
一 闭包
- 在嵌套函数内,内部函数使用外部非全局变量
- 作用:保护数据的安全性
- 装饰器的本质就是闭包
def func(): avg_lst = [] # 自由变量 def foo(pirce): avg_lst.append(pirce) avg = sum(avg_lst) / len(avg_lst) return avg return foo ret = func() print(ret(150000)) print(ret.__closure__) # 查询是不是闭包 print(ret.__code__.co_freevars) # 获取的是自由变量 print(ret.__code__.co_varnames) # 获取的是局部变量
二 迭代器
2.1 可迭代对象
查看 dir()
内部含有__iter__方法的对象,都是可迭代对象。
优点:使用灵活,可以直接查看值
缺点:占内存,不能迭代取值
2.2 迭代器
只要具有__iter__()方法__next__()方法就是迭代器
优点:节省内存,内存机制
缺点:使用不灵活,操作比较繁琐,不能直接查看元素
特点:一次性的(用完就没了),不可逆性(不可后退),惰性机制
2.3 将可迭代对象转换成迭代器
lst = [1,2,3,4,6] new_list = lst.__iter__() #将可迭代对象转换成迭代器
2.4 for 循环的本质
lst = [1,2,3,4,5,6,7,8,9] new_lst = lst.__iter__() #先转换成迭代器 while 1: try: print(new_lst.__next__()) except StopIteration: break
三 生成器
生成器本质就是迭代器,和迭代器不同的是,迭代器是python内置的,生成器是自己用代码构建的
3.1 生成器的构建方式
- 通过自己写的生成器函数
- 通过生成器推导式
- python内置函数或者模块提供
3.2 生成器函数
1. yield
将函数中的return换成yield,这样func就不是函数了,而是一个生成器函数
def func(): print(11) yield 22 ret = func() #产生一个生成器 print(ret)
输出结果:<generator object func at 0x000000000223FE08>
当我们调用函数的时候函数体里的代码会进行执行当执行到yield的关键字的时候,发现我们是想声明一个生成器.程序就会返回一个生成器给咱们
生成器取值和迭代器一样
def func(): print("111") yield 222 print("333") yield 444 gener = func() ret = gener.__next__() print(ret) ret2 = gener.__next__() print(ret2) ret3 = gener.__next__() # 最后一个yield执行完毕,再次__next__()程序报错 print(ret3)
生成器函数中可以写多个yield,当程序运行完最后一个yield,那么后面继续运行next()程序会报错,一个yield对应一个next,next超过yield数量,就会报错,与迭代器一样。
print(func().__next__()) # 坑 -- 会产生新的生成器 print(func().__next__())
yield与return的区别:
return一般在函数中只设置一个,他的作用是终止函数,并且给函数的执行者返回值。
yield在生成器函数中可设置多个,他并不会终止函数,next会获取对应yield生成的元素。yield会记录执行位置,在函数内部yield能将for和while循环临时暂停
2. seed
def gen(name): print(f'{name} ready to eat') while 1: food = yield print(f'{name} start to eat {food}') dog = gen('alex') next(dog) dog.send('骨头') # 还可以给上一个yield发送值 dog.send('狗粮') dog.send('香肠')
send和next()区别:
相同点:
send 和 next()都可以让生成器对应的yield向下执行一次。
都可以获取到yield生成的值。
不同点:
第一次获取yield值只能用next不能用send(可以用send(None))。
send可以给上一个yield置传递值.
3. yield from (python3中) 将可迭代对象元素逐个返回
def func(): lst1 = ['卫龙', '老冰棍', '北冰洋', '牛羊配'] lst2 = ['馒头', '花卷', '豆包', '大饼'] yield from lst1 yield from lst2 g = func() for i in g: print(i)
将第一个列表的元素全部返回后,再返回第二个列表