本篇文章围绕PEP-380提出的yield from
表达式内涵开展,并结合python官方关于yield-expression
的资料。
在PEP-380的Proposal部分有对yield from
表达式的基本阐述。它的格式为yield from expression
,其中expression
估值后可以是可迭代对象(iterater),但是expression
普遍是生成器(generator),一般被称为子生成器(subgenerator)。
子生成器(subgenerator)就像是白手套,帮主人打理事物。它将自己生产的成果直接传递给包含生成器对象(generator object)的方法(method)的调用者。调用者通过调用生成器对象的send()方法传递值给子生成器,子生成器将被传递的值用自己的send()方法处理;调用者通过生成器对象的throw()方法传递异常(exception)给子生成器,子生成器将传递进来的异常用自己的throw()方法处理。如果子生成器没有合适的方法进行相应的处理,调用的send()方法会提起AttributeError
异常或TypeError
异常,而throw()方法直接提起(raise)被传递的异常。
PEP-380为yield from expression
定义了语法规范。以下都是逐条对应翻译的:
- 子生成器-迭代器(与本文的子生成器是一个概念,后文一律用子生成器指代)将生产(yield)的值直接传递给调用者。
- 任何通过生成器对象send()方法传递的的值都会交给子生成器。如果被传递值是None,子生成器的send()方法被调用。子生成器的send()方法若提起
StopIteration
异常,则生成器对象被唤醒。任何其他异常都会被传播到调用者。 - 被抛入的除
GeneratorExit
之外的异常会经过子生成器的throw()传递。如果子生成器的throw()方法提起StopIteration
异常,生成器被唤醒。任何其他异常都会被传播到调用者。 - 如果
GeneratorExit
异常被抛入生成器,或生成器的close()方法被调用,那么子生成器的close()方法被调用,如果子生成器有该方法的话。如果子生成器的close()方法导致异常,异常会被传播到生成器。否则,GeneratorExit
异常在生成器中被提起。 - 子生成器终结时提起的
StopIteration
异常的value
属性就是yield from
表达式的值。 如果一个生成器中有
return expr
语句,那么当从生成器退出时,StopIteration(expr)
异常会被提起。在该PEP的Formal Semantics提到了使用的3种语法。
1.
RESULT = yield from EXPR
语句的等价表现形式:
_i = iter(EXPR)
try:
_y = next(_i)
except StopIteration as _e:
_r = _e.value
else:
while True:
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:
_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
2.在一个生成器函数中return value
语句等价于:raise StopIteration(value)
3.StopIteration
异常的表现是基于如下定义:
class StopIteration(Exception):
__init__(self,*args):
if len(args) >0:
self.value =args[0]
else:
self.value =None
Exception.__init__(self,*args)