yield扩展语法和发送方法

时间:2014-09-06 16:40:03

标签: python python-3.x generator yield

我读到了yield扩展语法,所以如果我有:

def numgen(N):
  for i in range(N):
    n = yield i
    if n:
      yield n

我可以考虑它:

def numgen(N):
  n = yield from range(N)
  if n:
    yield n

但是我注意到,如果我这样做,在我编写第二个生成器之后:

g = numgen(10)
next(g)
g.send(54)

我收到以下错误:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in gensquare
AttributeError: 'range_iterator' object has no attribute 'send'

那是怎么回事?如何将值发送到numgen生成器对象?

1 个答案:

答案 0 :(得分:5)

range()不是生成器,它没有generator.send() method

yield expression documentation中明确记录了这一点:

  

使用yield from <expr>时,它会将提供的表达式视为子实例。该子转换器生成的所有值都直接传递给当前生成器方法的调用者。 使用send() 传入的任何值以及使用throw() 传递的任何异常都会传递给基础迭代器(如果它具有相应的方法)。如果不是这种情况,则send()会引发AttributeErrorTypeError ,而throw()会立即引发传递的异常。

强调我的。

您正在尝试向range()迭代器发送值,但它没有.send()方法。

range() 只是序列,而不是生成器对象;你可以为它创建多个迭代器,你可以测试一个数字是否是序列的成员,询问它的长度等等。

请注意,您的“重构”根本不是一回事;在您的原始n中分配了您通过generator.send()发送的任何内容;在您的第二个版本yield from中返回子迭代器结束时引发的value异常的StopIteration属性。如果子迭代器本身是一个生成器,您可以通过手动引发StopIteration(value)或使用return语句来设置该值。 yield from无法返回使用generator.send()发送的值,因为这些值会传递给子生成器。

再次,从文档:

  

当底层迭代器完成时,凸起的StopIteration实例的value属性将成为yield表达式的值。它可以在提升StopIteration时显式设置,也可以在子迭代器是生成器时自动设置(通过从子生成器返回值)。

因此,您的第一个版本设置为接收N条消息,同时产生i for目标,任何已发送的值为true-thy,而另一个传递任何已发送的消息对于一个degelated-to生成器,然后只有StopIteration值,如果它是true-thy 一次,在委托迭代器完成之后。