背景:
通过列表生成式,我们可以直接创建一个列表,但是,受到内存限制,列表容量肯定是有限
的,而且创建一个包含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可以有返回值并且还支持多个,以元组的形式返回