【问题标题】:Why is this generator (using recursion) not producing intuitive results为什么这个生成器(使用递归)不能产生直观的结果
【发布时间】:2019-08-27 11:50:52
【问题描述】:

我编写了一个简单的生成器函数,它接受一个可能包含子列表的列表并尝试将列表展平:

所以 [1, [2, 3], 4, [5, [6, 7], 8]] 应该产生 1,2,3,4,5,6,7,8

如果我只是想打印出值(不是生成器),它看起来像这样,这很有效:

#  Code A
def flatten_list_of_lists(my_list):
    for element in my_list:
        if isinstance(element, list):
            flatten_list_of_lists(element)
        else:
            print(element)

my_list = [1, [2, 3], 4, [5, [6, 7], 8]]
flatten_list_of_lists(my_list)

按预期打印出 1,2,3,4,5,6,7,8

但是,当我将代码更改为:

#  Code B
def flatten_list_of_lists(my_list):
    for element in my_list:
        if isinstance(element, list):
            flatten_list_of_lists(element)
        else:
            yield element

for i in flatten_list_of_lists(my_list):
    print(i)

这只是将打印切换到产量,程序只打印出 1,4。

我将在下面粘贴实际有效的代码。但我想知道为什么以前的代码不起作用?如果代码 A 正确“打印”出数字,为什么代码 B 不能正确“输出”数字?

似乎我对生成器如何使用递归存在根本性的误解。

这段代码确实有效:

#  Code C
def flatten_list_of_lists_v2(my_list):
    for element in my_list:
        if isinstance(element, list):
            for sub_element in flatten_list_of_lists_v2(element):
                yield sub_element
        else:
            yield element

l = []
for element in flatten_list_of_lists_v2(my_list):
    print(element)

然后打印出 1,2,3,4,5,6,7,8

只是一点背景,我刚看完这个视频: https://www.youtube.com/watch?v=LelQTPiH3f4

在那里他解释说,当您设计生成器时,只需在您想要输出的地方放置一个打印件,看看您是否得到正确的结果,然后将打印件切换到输出。所以我猜他的建议并不适用于所有情况,我只是想了解原因。

【问题讨论】:

  • code A中,将flatten_list_of_lists(element)更改为yield from flatten_list_of_lists(element)print(element)更改为yield element
  • 在代码 B 中,flatten_list_of_lists(element) 是一个返回生成器的语句,但没有对该对象执行任何操作,因此代码继续执行,直到到达下一个 yield 语句。
  • 本质上类似于stackoverflow.com/q/31221826/1126841;您忽略了对flatten_list_of_lists_v2 的递归调用的返回值(或者更确切地说,可以从中提取的值)。如果您是返回值而不是打印它们,那么您在第一个版本中也会遇到同样的问题。
  • 该视频给出了糟糕的建议。打印一个值与返回或产生一个值非常不同。
  • 比较 x = (lambda x: x)(3)x = print(3)(假设您没有使用 Python 2 的 print 语句)。

标签: python recursion generator


【解决方案1】:

一个简单的错误-

def flatten_list_of_lists(my_list):
    for element in my_list:
        if isinstance(element, list):
            # add yield from
            yield from flatten_list_of_lists(element)
        else:
            # yield, not print
            yield element

my_list =  [1, [2, 3], 4, [5, [6, 7], 8]]

for e in flatten_list_of_lists(my_list):
  print(e)

输出

1
2
3
4
5
6
7
8

【讨论】:

  • 但是为什么我的代码不起作用...我用一个子列表调用 flatten_list_of_lists 以便调用它也应该产生该子列表中的值
  • 因为flatten_list_from_lists 返回了一个生成器,而您没有对它任何操作!这就像说 (1 + 1) 但没有将其分配给变量或打印它......它的计算结果为 2 但随后消失了
  • 您的第一个版本有效,因为它没有返回任何内容;它打印值。
  • 谢谢,我想我现在明白了。基本上,我调用这个生成器的循环只会返回“第一个生成器”,而不是在生成器中创建的任何未来生成器。
  • 也谢谢你,直到现在我才听说过'yield from'。如果有人感兴趣,这里有一些东西。 utcc.utoronto.ca/~cks/space/blog/python/…
猜你喜欢
  • 2013-02-19
  • 2011-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-12
相关资源
最近更新 更多