【问题标题】:yield extended syntax and send methodyield 扩展语法和发送方法
【发布时间】:2014-09-06 16:40:02
【问题描述】:

我读到了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 生成器对象发送值?

【问题讨论】:

    标签: python python-3.x generator yield


    【解决方案1】:

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

    这在yield expression documentation中有明确记录:

    当使用yield from &lt;expr&gt; 时,它将提供的表达式视为子迭代器。该子迭代器生成的所有值都直接传递给当前生成器方法的调用者。 任何用send() 传入的值和任何用throw() 传入的异常如果有适当的方法,就会被传递给底层迭代器。如果不是这种情况,那么send() 将引发AttributeErrorTypeError,而throw() 将立即引发传入的异常。

    强调我的。

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

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

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

    再次,来自文档:

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

    因此,您的第一个版本设置为接收 N 消息,产生 i for 目标和任何发送的值都是 true-thy,而另一个将任何发送的消息传递给 degelated-to 生成器,那么在委托迭代器完成后,如果它是 true-thy once,则只会产生 StopIteration 值。

    【讨论】:

    • 没看懂,我只是在python3.4中试了一下,可以,不用括号
    • @antox:啊,是的,yield from 在对象上调用iter(),我的错。
    • '[...] while throw() 只会立即引发传入的异常。'异常会在生成器对象中抛出吗?在调用throw() 的地方?
    • @antox: .throw() 引发生成器暂停的异常。在这种情况下,在yield from 行。
    • "如果使用 send() [...] 传入的任何值都将传递给底层迭代器,如果它具有适当的方法。"迭代器应该定义哪些方法来获取这些值?
    猜你喜欢
    • 2019-07-24
    • 2021-10-09
    • 2014-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-15
    相关资源
    最近更新 更多