生成器/推导式
1、什么是生成器?
可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其他数据类型需要调用自己内置的__iter__方法),所以生成器就是可迭代对象;
2、生成器在python中的表现形式?
- 生成器函数:常规函数定义,但是使用yield语句而不是使用retum语句返回结果,yield语句一次返回一个结果,在每个结果中间挂机函数的状态,以便下次从他离开的地方执行;
- 生成器表达式:类似于列表推导,但是生成器返回按需要产生结果的一个对象,而不是一次构建一个列表
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#生成器函数(只要函数内部包含有yield关键字,那么函数名()的到的结果就是生成器,并且不会执行函数内部代码) cp = [1,2,3,4,5] def test(): yield 1 yield 2 yield 3 date = test() print(next(date)) print(next(date)) print(next(date))
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#三元表达式 name = "lw" res = "sb" if name == "lw" else "帅哥" print(res) egg1 = ["鸡蛋 %s" %i for i in range(10) if i > 5 ] print(egg1) #正常列表(在内存中存储) egg_list = [] for i in range(10): egg_list.append("鸡蛋 %s" %i) print(egg_list) #列表解析(在内存中存储) egg = ["鸡蛋 %s" %i for i in range(10)] print(egg) #生成器表达式(基于迭代器协议转换成可迭代对象,不占内存) laomuji = ("鸡蛋 %s" %i for i in range(10)) print(laomuji) #<generator object <genexpr> at 0x000001A6F46231A8> print(laomuji.__next__()) #等于next(laomuji)
3、生成器取值的几种方式
- 直接调用生成器内置的__next__方法;生成器内的数据取完,在取会抛出StopIteration
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def func(): print(1) yield 5 # 我的函数走到这了 print(2) yield 9 # 我的函数走到这了 g = func() # 生成一个生成器 print(g.__next__()) print(g.__next__()) # 每次取值会从上一个yield开始 print(g.__next__()) # 生成器内的数据取完,在取会抛出StopIteration
- 生成器调用send()方法,send()相当于(next + 传值),传值给yield,第一次调用生成器的时候使用send里边的值必须是None
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def func(): print(1) a = yield 2 # 1.挂起 2.返回值 3.接受值 print(a) print(3) b = yield 4 print(b) c = yield 9 g = func() # 生成一个生成器 print(g.__next__()) print(g.send('123')) print(g.send('234')) #第一次调用生成器的时候使用send里边的值必须是None
4、简述yield与yield from的区别
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def generator(): for i in range(5): yield i t = generator() print(t.__next__()) def generator_1(): yield 1 yield 2 yield 3 yield 4 yield 5 t1 = generator_1() print(t1.__next__()) 上面这两种方式是完全等价的,只不过前者更简单一些。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def generator1(): item = range(10) for i in item: yield i def generator2(): yield ‘a‘ yield ‘b‘ yield ‘c‘ yield from generator1() #yield from iterable本质上等于 for item in iterable: yield item的缩写版 yield from [11,22,33,44] yield from (12,23,34) yield from range(3) for i in generator2() : print(i) 从上面的代码可以看书,yield from 后面可以跟的式子有“ 生成器 元组 列表等可迭代对象以及range()函数产生的序列”
def test(): for i in range(10): yield i a = test() print(a.__next__()) for j in a: print(j) def test(): yield from range(10) b = test() print(b.__next__()) for j in b: print(j)
5 推导式
# 推导式:
# 1.列表
# 2.集合
# 3.字典
# 4.生成器表达式(只要是小括号的就是生成器表达式)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
li = [] for i in range(10): li.append(i) print(li) print([i for i in range(10)]) [结果 语法] #容器 li = [] for i in range(10): if i%2 == 1: li.append(i) print(li) print([i for i in range(10) if i%2 == 0]) # 过滤(筛选) li = [] for i in range(10): for em in range(3): li.append(em) print(li) print([j for i in range(10) for em in range(3) for j in range(5)]) 集合推导式 s = {i for i in range(10)} print(s) 字典推导式 print({i:i+1 for i in range(10)}) 生成器表达式 g = (i for i in range(10))
总结:
# 1.生成器的本质就是一个迭代器
# 2.生成器一定是一个迭代器,迭代器不一定是一个生成器
# 3.生成器是可以让程序员自己定义的一个迭代器
# 4.生成器的好处,节省内存空间
# 5.生成器的特性 一次性的,惰性机制,从上向下
# 6.send相当于 next+传值,第一次触生成器的时候,如果使用send(None)值必须是None,一般我建议你们使用__next__
# 7. python2 iter() next()
# python3 iter() next() __next__() __iter__()
# 8.yield from 将可迭代对象元素逐个返回