闭包, 迭代器, 生成器

Kwong 2019-11-05

一 闭包

  1. 在嵌套函数内,内部函数使用外部非全局变量
  2. 作用:保护数据的安全性
  3. 装饰器的本质就是闭包
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 生成器的构建方式

  1. 通过自己写的生成器函数
  2. 通过生成器推导式
  3. 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)

将第一个列表的元素全部返回后,再返回第二个列表

相关推荐