【问题标题】:Difference between `return iterator` and `yield from iterator``return iterator` 和 `yield from iterator` 之间的区别
【发布时间】:2018-01-19 02:38:29
【问题描述】:

我正在尝试实现我自己的itertools.compress 版本,问题是我偶然发现了返回类型。我的意思是这两个函数都返回一个迭代器,但我认为第二个函数不被视为生成器函数,因为内部没有 yield 语句。所以我的问题是,这两个实现是等价的吗?

def compress (seq, selectors):
    from operator import itemgetter
    fst = itemgetter (0)
    snd = itemgetter (1)
    yield from map (fst, filter (snd, zip (seq, selectors)))

def compress (seq, selectors):
    from operator import itemgetter
    fst = itemgetter (0)
    snd = itemgetter (1)
    return map (fst, filter (snd, zip (seq, selectors)))

【问题讨论】:

    标签: python python-3.x itertools yield-from


    【解决方案1】:

    不完全是。

    yield from seq 等价于for i in seq: yield i

    这意味着您的第一个实现是一个生成器,它从 map() 的结果中生成每个项目,而您的第二个实现返回地图对象。

    【讨论】:

      【解决方案2】:

      虽然它们可能看起来非常相似,即使输出结果也是如此,但它们并不等同。

      查看这些基本代码示例,将str 映射到range(100)

      def do_yield_from():
          yield from map(str, range(100))
      
      
      def do_return():
          return map(str, range(100))
      
      print(do_yield_from())
      print(do_return())
      
      >>> <class 'generator'>
      >>> <class 'map'>
      

      第一个函数是generator,从do_yield_from 和缩短版本的

      中产生结果
      for r in range(100): yield str(r)
      

      第二个函数返回map 的实例,它是iterator 而不是generator

      由于第一个函数是generatoryield from 的性能优于do_return

      import timeit
      print(timeit.timeit(do_yield_from))
      >>> 0.53931242968009
      
      print(timeit.timeit(do_return))
      >>> 1.467075402143485
      

      【讨论】:

      • returning 的性能差异是否相关?所花费的时间相差不到 微秒迭代时间本身要大得多;如果我们要衡量绩效,我会改为衡量。 (尽管即使是这种差异也可能无关紧要且可以忽略不计。)
      • 我进行了一些测试:迭代器上的迭代 do_return()at least 25% faster!
      【解决方案3】:

      所以我的问题是,这两种实现是否等效?

      一点也不。

      yield fromreturn 是两个不同的、截然不同的句法结构。

      yield from 是在PEP380 中引入的语法。这称为生成器委托From the documentation:

      PEP 380 添加了yield from 表达式,允许生成器将其部分操作委托给另一个生成器。这允许将包含 yield 的一段代码分解出来并放置在另一个生成器中。此外,子生成器可以返回一个值,并且该值可供委托生成器使用。

      return 但是具有完全不同的行为。 From the documentation:

      return 只能在语法上嵌套在函数定义中,而不是在嵌套的类定义中。

      如果存在表达式列表,则对其进行评估,否则将替换为无。

      return 以表达式列表(或None)作为返回值离开当前函数调用。

      基本上yield from &lt;iter&gt; 等同于for element in &lt;iter&gt;: yield element,而return 将只返回一个值。 就您而言,我相信 yield from 是您正在寻找的。您想要 yield 来自 map 迭代器的值,而不是 return 迭代器本身。

      【讨论】:

      • 问题是关于返回一个迭代器,所以语句“return 将简单地返回一个值”只是一个技术性问题。从外观上看,两者是等价的。
      • 我想严格按照功能@cube。但是还是有区别的。 yield from 版本的compress 返回一个生成器对象,而return 版本的compress 返回一个迭代器对象。正如@Wondercricket 下面提到的,使用yield from 是更有效的选择。所以至少在这种情况下,我仍然认为重要的是要明确提出的两个选项之间存在区别。
      猜你喜欢
      • 2016-09-08
      • 2016-08-20
      • 2015-06-22
      • 1970-01-01
      • 2010-11-21
      • 2016-06-27
      • 2014-11-11
      • 2012-03-13
      相关资源
      最近更新 更多