简述
每当看到yield from,都有些心虚,因为不了解。今天找时间了解了一下,不得不说官网的英语太难了,哎~,先把看懂的说下一吧
为啥用yield from呢
- 第一个理由
RESULT = yield from EXPR
上面的代码是等于下面的代码的
#### 工作代码
_i = iter(EXPR)
try:
_y = next(_i)
except StopIteration as _e:
_r = _e.value
else:
while 1:
try:
_s = yield _y
except GeneratorExit as _e:
try:
_m = _i.close
except AttributeError:
pass
else:
_m()
raise _e
except BaseException as _e:
_x = sys.exc_info()
try:
_m = _i.throw
except AttributeError:
raise _e
else:
try:
_y = _m(*_x)
except StopIteration as _e:
_r = _e.value
break
else:
try:
if _s is None:
_y = next(_i)
else:
_y = _i.send(_s)
except StopIteration as _e:
_r = _e.value
break
RESULT = _r
也就是说用了yield from
,我们不用写这么多代码来解决异常的情况了
- 第二个理由
yield from
帮我们做了迭代
def generator_one():
local_list = ["one", "two", "three"]
yield from local_list
if __name__ == "__main__":
test_one = generator_one()
for temp_part in test_one:
print(temp_part)
上面的代码等于
def generator_one():
local_list = ["one", "two", "three"]
for part in local_list:
yield part
if __name__ == "__main__":
test_one = generator_one()
for temp_part in test_one:
print(temp_part)
yield from的几个特点
- yield from后面接的表达式,返回的值是直接发送给调用者的。这个特点比较绕,我试着解释一下。我们从上面的原理代码中可以看出迭代器产生的值,最终还是被yield修饰,也就是当我们在
print(test_two.send(1))
这样的类似语句调用,yield from的生成器时,最终调用的还是迭代器的__next__()方法取值。
运行一下下面的代码,你会发现print("Is Over")
是一直不运行的,也就是说print(test_two.send(1))
语句调用的是generator_one返回的生成器
def generator_one():
local_list = ["one", "two", "three"]
for part in local_list:
yield part
def generator_two():
while True:
yield from generator_one()
print("Is Over")
if __name__ == "__main__":
test_two = generator_two()
print(type(test_two))
print(test_two.send(None))
print(test_two.send(1))
print(test_two.send(1))
-
如果除了GeneratorExit 之外的异常,传给了yield from,那么迭代器的throw()方法将被调用,对应原理代码中的
_i.close
-
如果GeneratorExit 或者生成器调用了close()方法,那么迭代器的close()方法将被调用,对应原理代码中的
_i.throw
推荐一个大哥写的文章,关于yield from的
https://www.lagou.com/lgeduarticle/75809.html
如果对本文有疑问或者发现不对的地方,希望能给予评论或者进群630300475,讨论一下。