【问题标题】:How to desugar a yield from syntax in Python?如何从 Python 中的语法中脱糖?
【发布时间】:2020-01-24 05:16:51
【问题描述】:

现在我正在研究 yield-from 和 await 语法之间的区别。从官方 python 文档中,yield-from generator() 只是以下代码的语法糖:

for i in generator(): yield i

但我无法在下面的示例中对 yield-from 进行脱糖。

def accumlate():
    # context
    accumlator = 0
    while True:
        next = yield
        if next is None:
            return accumlator
        accumlator += next


def gather(tallies):
    while True:
        tally = yield from accumlate() # (*)
        tallies.append(tally)

def main():
    tallies = []
    accumlator = gather(tallies)
    next(accumlator)
    for i in range(4):
        accumlator.send(i)

    accumlator.send(None)
    for i in range(6, 10):
        accumlator.send(i)
    accumlator.send(None)
    print(tallies)

if __name__ == "__main__":
    main()

我尝试将 yield-from 替换为 for-in 版本,但它不起作用,因为 for-in 不能放在 tally 变量的右侧。用星号标记的代码的确切脱糖是什么?

【问题讨论】:

    标签: python yield-from


    【解决方案1】:

    @DerteTrdelnik 的回答基本上是正确的,只是您根本不必修改 accumlate 函数,因为生成器已经自动引发 StopIteration 并将返回值作为参数来构造异常对象生成器返回没有任何收益。

    摘自StopIteration的文档:

    当生成器或协程函数返回时,一个新的StopIteration 引发实例,函数返回的value 用作 异常构造函数的value参数。

    因此,您只需像这样对gather 函数“脱糖”:

    def gather(tallies):
        while True:
            a = accumlate()
            a.send(None)
            while True:
                try:
                    a.send((yield))
                except StopIteration as e:
                    tallies.append(e.value)
                    break
    

    【讨论】:

      【解决方案2】:

      result = yield from generator()不易被替换,是如何获取生成器返回值的方式

      https://www.python.org/dev/peps/pep-0380/#proposal

      要在不使用 yield from 的情况下模拟一些正在发生的事情,我们必须修改两个生成器

      def accumlate():
          # context
          accumlator = 0
          while True:
              next = yield
              if next is None:
                  raise StopIteration(accumlator)
              accumlator += next
      
      
      def gather(tallies):
          internal_acc = accumlate()
          internal_acc.send(None)
          while True:
              try:
                  number_to_add = yield
                  internal_acc.send(number_to_add)
              except StopIteration as e:
                  internal_acc = accumlate()
                  internal_acc.send(None)
                  tallies.append(e.value)
      

      accumlate 不再返回,但要加注,gather 必须尝试除加注,

      internal_acc 用完后,在 except 中创建一个新的

      如 pep0380 中所见,它还有更多内容,但基本上生成器返回是一个加薪,而产量来自是一个紧凑的捕获

      【讨论】:

        猜你喜欢
        • 2015-05-24
        • 2014-01-03
        • 1970-01-01
        • 2014-03-30
        • 2021-07-09
        • 2018-12-07
        • 2011-08-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多