一,什么是生成器
可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其他数据类型需要调用自己内置的__iter__方法),所以生成器是可迭代对象。
二,生成器分类在python中的表现形式
1,生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数状态,以便下次从它离开的地方继续执行day18-5.py
def test(): yield 1 yield 2 g=test() print(g) print(g.__next__()) print(g.__next__()) <generator object test at 0x000001D40CF6F3B8> 1 2
不同于return可以yield多个值,因为是可迭代对象所以有next方法
2,生成器表达式:类似于列表推导,但是生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表
三,三元表达式,如果表达式成立返回前面的值否则返回后面的值day18-7.py
name='zhangsan' print('SB' if name == 'zhangsan' else '帅哥')
四,列表表达式,举例说明 day18-8.py
#使用for循环实现生鸡蛋 egg_list=[] for i in range(10): egg_list.append('鸡蛋%s' %i) print(egg_list) #使用列表表达式生鸡蛋 l=['鸡蛋%s'%i for i in range(10) ] print(l) ['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9'] ['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']
使用for循环和列表表达式生成是结果是一样的
使用三元表达式加一个if判断条件(三元表达式可以是三元也可以是二元,但是不能是四元)
l=['鸡蛋%s'%i for i in range(10) if i>5] print(l) ['鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']
以上使用表达式生成的列表直接在内存中,可以使用生成器表达式
egg_list=['鸡蛋%s'%i for i in range(10)] laomuji=('鸡蛋%s'%i for i in range(10)) print(laomuji) print(next(laomuji)) #next的本质就是调用__next__ print(laomuji.__next__()) print(next(laomuji)) <generator object <genexpr> at 0x000001D39C97F3B8> 鸡蛋0 鸡蛋1 鸡蛋2
PS:不能无限制的next因为定义生成器的时候定义了范围0-9所以最多到鸡蛋9
总结:
1,把列表解析的[]换成()得到的就是生成器表达式
2,列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存
3,Python不但所以迭代器协议让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如,sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接作用计算一系列值的和
print(sum(x ** 2 for x in range(4))) 14
PS:生成器只能遍历一次(for,next,list等操作均为遍历),一次遍历以后里面的值为空了
day18-9.py
#定义生成器函数遍历0 1 2 3 def test(): for i in range(4): yield i #生成器函数执行赋值给t t=test() #列表表达式赋值 t1=(i for i in t) t2=(i for i in t1) print(t1) #遍历输出[0, 1, 2, 3] print(list(t1)) #因为t1已经遍历过一次了使用遍历t2输出为一个空列表 print(list(t2)) <generator object <genexpr> at 0x0000020A158D3938> [0, 1, 2, 3] []