益智:无循环/进口的递归发生器

时间:2012-09-18 14:12:12

标签: python generator

今天是发电机。我今天看到一个question想要找到一种方法来递归地压缩列表而不使用循环和导入。 tobias_k使用以下代码回答:

def flatten(test_list):
    if isinstance(test_list, list):
        if len(test_list) == 0:
            return []
        first, rest = test_list[0], test_list[1:]
        return flatten(first) + flatten(rest)
    else:
        return [test_list]

有没有办法创建一个生成器(保持规则:没有导入,循环)?

注意:它纯粹是教育性的。我知道这不是最好的主意,但不知道该怎么做。

3 个答案:

答案 0 :(得分:4)

在Python 3.3(开发版)中,您可以使用yield from构造来避免显式循环:

def flatten(x):
    if isinstance(x, list):
        if x:
            first, rest = x[0], x[1:]
            yield from flatten(first)
            yield from flatten(rest)
    else:
        yield x

在当前版本中,我无法想到不使用itertools.chain的解决方案。

答案 1 :(得分:4)

generator function是一个包含至少一个yield statement和没有return语句的函数。当调用生成器函数时,它返回一个生成器迭代器,当迭代时(例如通过for循环,或显式地使用next)运行函数体,冻结其状态并将控制返回到每个yield语句(以及Python 3.3,yield from语句中的调用者。)

Python函数内部的流控制总是向前发展;没有像设置当前帧{1}那样的黑客(正如(愚人节)goto statement所做的那样),控制达到早期点的唯一方法是使用循环(f_linenofor)。因此,如果没有循环或while,可以调用生成器迭代器的最大次数受生成器函数中yield from语句数量的限制。

请注意,编写返回迭代器的yield很容易;采用原始解决方案并编写flatten即可。但那不是生成器迭代器,函数也不是生成器函数。

这是一个滥用return iter(flatten(first) + flatten(rest))来实现无循环迭代的实现。不幸的是,它必须使用f_lineno

import sys

答案 2 :(得分:-1)

完成单行列表理解:

def flatten (test_list):
    return [element for temp in test_list for element in flatten(temp)] if isinstance(test_list, list) else [test_list]


print(flatten([1, [2, 1, [3, 6, 7]], [1, 2, [3, 2, 3], 4, [1, 2, 3, 4, 5]]]))
#[1, 2, 1, 3, 6, 7, 1, 2, 3, 2, 3, 4, 1, 2, 3, 4, 5]