【问题标题】:Generator set in loop being overwritten循环中的发电机组被覆盖
【发布时间】:2019-05-04 20:51:33
【问题描述】:

我正在尝试编写一个函数来基于列表构建一个扁平的生成器树。所以如果我有一个项目列表,我想从一个空生成器开始,并在第一个项目和空生成器上调用一个函数,然后在第二个项目上调用函数和第一个函数调用的输出,然后调用第三个项目的函数和第二个函数调用的输出,依此类推。 重要的是,在最终生成器上调用 next 之前,我不想真正评估 任何东西

所以,如果我们在列表和生成器上调用的函数被称为foo,(显然它也输出一个生成器),并且项目列表是list...

现在,我有一个原型,如下所示:

>>> tree = iter([{}])
>>> tree = chain.from_iterable((foo(list[0], p) for p in tree))
>>> tree = chain.from_iterable((foo(list[1], p) for p in tree))
>>> tree = chain.from_iterable((foo(list[2], p) for p in tree))
>>> list(tree)

这确实有效。它会正确评估所有内容,最重要的是不会不必要地评估任何内容(以整数开头的行是在实际情况下打印的日志:

>>> next(tree)
Called on 0
Called on 1
Called on 2
Result A
>>> next(tree)
Called on 1
Called on 2
Result B

不幸的是,当我尝试使用循环使其在任意长度的 tail 上工作时:

tree = iter([{}])
for item in list:
    tree = chain.from_iterable((foo(item, p) for p in tree))

它不起作用。相反,tree 变量设置为在 empty 可能性上调用 foo 的结果,就好像它是唯一被评估的东西一样!我不知道发生了什么,虽然我有一个 预感 那是因为有一个指针什么的。

任何帮助将不胜感激!

【问题讨论】:

  • 是的,这似乎是相关的......如果由此推测 Python 中的生成器表达式不会将其范围保存在表达式的正确部分,它们会在执行时使用变量.不过,我不确定如何解决这个问题,特别是因为保存中间 trees 不起作用。

标签: python pointers iterator generator


【解决方案1】:

递归的调用在这里很清楚:

import itertools as it


def lazy_reduce(list_, tree_base, i=None):
  if i is None:
    i = len(list_)

  if i < 0:
    return iter(tree_base)

  return it.chain.from_iterable(
    foo(list_[i], p)
    for p in lazy_reduce(list_, tree_base, i - 1)
  )

【讨论】:

  • 在我尝试使用链之前,它的原始版本是递归的。但我不想通过堆栈大小来限制项目的数量,因为这是针对使用该系统作为拥有多个语句的方式的解释器。
  • 如果是这种情况,您可以使用手动管理的堆栈和for 循环轻松模仿递归。
  • 我已经通过将每个中间值推入堆栈并让下一个值取决于前一个值(按索引而不是 [-1] 因此后续更改不会搞砸)来尝试过这个似乎没有用——它做了完全相同的事情。
  • 事实证明,这是因为它们引用了周围范围的值,它们不采用闭包。因此,如果 i 在创建生成器时为 3,但在创建完成时为 9,则所有生成器都将使用 9。
【解决方案2】:

为避免生成器作用域的问题,您可以创建一个具有自己作用域的函数:

def add_item(tree, item):
    return chain.from_iterable((foo(item, p) for p in tree))

tree = iter([{}])
for item in list:
    tree = add_item(tree, item)

【讨论】:

  • 我试图避免调用函数来执行此操作。因为那时项目的数量受到堆栈大小的限制。我正在尝试为仅通过此算法顺序执行的编程语言执行此操作,这样会限制程序大小。
猜你喜欢
  • 2021-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多