闭包, 迭代器, 生成器
一 闭包
- 在嵌套函数内,内部函数使用外部非全局变量
- 作用:保护数据的安全性
- 装饰器的本质就是闭包
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)
将第一个列表的元素全部返回后,再返回第二个列表