生成器与yield关键字

背景:

        通过列表生成式,我们可以直接创建一个列表,但是,受到内存限制,列表容量肯定是有限

的,而且创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前

面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

      所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算

后续的元素呢?这样就不必创建完整的list,从而节省大量的空间,在Python中,这种一边循环一

边计算的机制,称为生成器:generator 

如何得得到自定义的迭代器:

在函数内一旦存在yield关键字,调用函数并不会执行函数体代码,会返回一个生成器对象,生成器

即自定义的迭代器

fun():
    print('第一次')
    yield 1
    print('第二次')
    yield 2
    print('第三次')
    yield 3
g=fun()
print(g)
g.__iter__()
g.__next__()

# 会触发函数体代码的执行,然后遇到yield停下来,将yield后的值当作本次调用结果返回
res1=g.__next__()
print(res1)

## 生成器其实就是一个自定义的迭代器
# res.__next__() # 只要你调用next方法,代码就会走到函数中第一个yield关键字所在的位置停住
# res.__next__() # 代码从上一次yield停住的地方继续往下执行,走到遇到下一个yield停住

yield表达式形式

# x = yield 返回值
def dog(name):
    food_list=[]
    print('道哥%s准备吃东西啦。。。'%name)
    while True:
        # x拿到的是yield接受到的值 
    	x=yield food_list # 值没有给返回值,而是交给了yield,再由yield转交给了x
        food_list.append(x)
        print('道哥%s吃了%s'%(name,x))
g=dog('alex')
g.send(None) # 先初始化,等同于next(g)

g.send('一根骨头')
g.send('肉包子')# send可以用来多次传值
g.close()
g.send('1111') #关闭之后无法传值

yield功能:先从当前挂起的位置先收一个值给x,在本次运行过程中碰见一个新的yield再返回值

生成器表达式

列表生成式
res = [name for name in names_list]
print(res) # 就是一个列表

res1 = (name for name in names_list)
print(res1)
names_list = ['kevin', 'jerry', 'tony', 'oscar']
res1 = (name for name in names_list)
print(res1) # <generator object <genexpr> at 0x00000218F4569CF0>

print(res1.__next__())
print(res1.__next__())
print(res1.__next__())
print(res1.__next__())

"""生成器表达式如果不使用数据,就不给你数据"""

把迭代器、生成器看成是一个工厂,什么时候需要数据工厂就给你加工数据

目的:就是为了节省内存空间

yield和return的对比

yield:

1. 代码遇到yield不会停止,而是停住

 2. yield也可以有返回值,并且还支持多个,以元组的形式返回

3. yield可以把一个函数变成生成器,next取值

return:

1. 代码遇到return就会停止

2. return可以有返回值并且还支持多个,以元组的形式返回

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值