一、什么是生成器
可以理解为是一种数据类型,这种数据类型自动实现了迭代器协议(其他数据类型需要调用自身内置的__iter__方法),所以生成器是可迭代对象。
二、生成器分类及在python中的表现形式
1、生成器函数:
常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数状态,以便下次从它离开的地方继续执行。
def test():
yield 1
g = test()
print(g)
print(g.__next__())
<generator object test at 0x00000180BCB692B0>
1
不同于return可以yield多个值,因为是可迭代对象所以有next方法
2、生成器表达式:类似于列表推导,但是生产器返回按需要产生结果的一个对象,而不是一次构建一个结果列表。
三、三元表达式,如果表达式成立返回前面的值否则返回后面的值
name='zhangsan'
print('SB' if name == 'zhangsan' else '帅哥')
四、列表表达式。
#使用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,所以最多九个鸡蛋
总结:
1、列表解析的[]换成()得到的就是生产器表达式
2、列表解析和生成器表达式都是一种便利的编程方式,只不过生产器表达式跟节省空间
3、python不但可以通过迭代器协议让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。列如,sum函数是python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接计算一系列的和。
print(sum( i for i in range(10)))
45
PS 生成器只能遍历一次,(for、next、list等操作均为遍历),一次遍历以后里面的值为空了
#定义生成器函数遍历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]
[]