python学习——yield和yield from
一、先来看看yield返回的是什么东东
- yield关键字只能在函数中使用,否则会抛出语法异常
- 咱们知道只要在函数中存在
yield
关键字,那么这个在调用这个函数的时候,其返回值就是一个生成器对象,下图咱们引入from collections.abc import Generator
生成器类,判断函数返回的是不是Generator的实例 - 既然知道是
Generator
,那么要讲Generator
就需要再谈谈Iterable
可迭代对象和Iterator
迭代器 - 先看继承关系,
Iterator
是继承自Iterable
,而Generator
又是继承自Iterator
- 所以说生成器具有可迭代对象和迭代器的所有特性
二、可迭代对象
- 什么是可迭代对象?
- 可以使用for循环遍历的,那就是可迭代对象。比如
for i in range(10): print(i)
会打印0-9,其中list str dict tuple
等都是可迭代对象 - 其实只要实现了
__iter__
魔法方法,那么它就是可迭代对象 - 自定义一个可迭代对象,只要实现
__iter__
方法就行
三、什么是迭代器
- 只要实现
__iter__
和__next__
方法,就是迭代器 - 迭代器可以使用
next()
方法获取下一个的值,迭代器也是一个可迭代对象,因为它继承了Iterable
,而且他也实现了__iter__
方法 - 像
list str dict tuple
等虽然是可迭代对象,但是却不是迭代器 - 他们也不能使用
next()
获取下一个值 - 自定义迭代器,需要实现
__iter__
和__next__
方法
三、生成器
- 上面也说过了,生成器需要使用
yield
关键字,yield from
也是返回一个生成器的,放在函数内部即可返回一个生成器 - 也可以使用列表解析,不过需要将方括号
[]
换成中括号()
四、生成器、迭代器、可迭代对象总结
- 生成器继承迭代器,迭代器继承可迭代对象,可迭代对象继承
ABCMeta
抽象基类 - 可迭代对象特性,可以使用
for
循环遍历,但是不能使用next()
方法 - 迭代器特性,也是可迭代对象,自然可以使用
for
循环遍历,也可以使用next()
方法获取下一个值 - 生成器特性,既是可迭代对象,也是迭代器,可以使用
for
和next()
,生成器还有send()
、throw()
和close()
方法
五、再谈yield
- 咱们现在已经知道yield放在函数内部,会返回一个生成器,可以使用
for
或next
获取下一个值 - 那么咱们现在来看一下
yield
后面能跟什么类型的值,而使用for
遍历后,打印的值是什么 - 可以看到,yield后面可以跟任意值,而且返回来的和原来一样,即
yield
后面是什么,返回来的值就是什么 - 甚至可以yield一个函数
六、yield from
-
yield from
也是返回一个生成器的 - 看一下
yield from
后面可以跟什么类型,其实yield from
后面只能跟可迭代对象iterable
,虽然上图跟的是一个int类型的值,虽然没有报错,但是,咱们用for
循环打印一下便知 - 所以
yield from
后面必须跟一个可迭代类型 - 咱们看看yield from和yield有什么区别,咱们
yield 'abcd'
,打印的是’abcd’,但是yield from 'abcd'
打印的却是a b c d
四个分开的字母
- 其实
yield from iterable
内部帮咱们这样做 - 其实
yield from
不仅仅只有这么简单,由于还涉及到协程,所以这里就不说那么多
七、总结
-
yield
和yield from
都只能用于函数内部 - 都会返回一个生成器对象
-
yield
和yield from
后面能跟的值有所差别,yield
后面能跟几乎所有类型的值,而且使用for
循环遍历打印之后的值和后面所跟的值一样,比如yield range(10)
,打印之后也是range(10)
;而yield from
后面能跟的类型只能是可迭代对象,而且yield from
内部会帮我们做一层for
遍历,比如yield from range(10)
,其实内部是做了for i in range(10): yield i
这样的一步操作,另外yield from
和协程、异步有所挂钩