Pypy:为什么一个“更简单”的嵌套列表需要更长时间才能展平?

时间:2012-06-20 18:34:02

标签: recursion pypy flatten

我需要展平一些嵌套列表。在编写了flatten函数之后,我自然会试着看看有多少种方法可以打破它。我终于通过pypy运行了它,并且很高兴地发现,当列表真正深入时,pypy的运行速度明显快于cpython。

然而,我看到一种奇怪的情况,即一个更大,更复杂的列表,具有更多元素的测试实际上比“更简单”列表执行得更快。

测试1,其元素较少,运行速度(使用时间pypy ./script.py)比测试2慢一秒。

def flatten(lol):
    if not any([isinstance(i, list) for i in lol]):
        return lol

    flatter = [i for i in lol if not isinstance(i, list)]
    for sublist in lol:
        if isinstance(sublist, list):
            flatter.extend(sublist)
    return flatten(flatter)

def silly(l):
    return [l, [l]]

nested_function = [["kaplutis", ["mucus", ["my brain", ["is","filled",["with",["pus",]]]]]], "santa gertrudis",[[[[["innermost",flatten(["in", "func"])]]]]]]

tuples = ["empty tuple retained-->", (), ("2-tuple not flattened",), ("I'm the only thing in this tuple")]

dicts = [{"hip": "hop", "ster": "toad"}]

lone_dict = {"lone": 1, "dict": 2}

silly_list = ["1"]
for i in range(20):
    silly_list = silly(silly_list)

# test 1 - only the absurdly nested list
print(len(flatten(silly_list)))

# test 2 - absurdly nested list, with 
lol = [nested_function, tuples, dicts, lone_dict, silly_list]
print(len(flatten(lol)))

我唯一可以想到的是,当JIT在第二次测试中处理“silly_list”之前的更简单的嵌套列表时,我遇到了一些意外的优化。

2 个答案:

答案 0 :(得分:1)

这种特殊的压扁功能确实击中了cpython和pypy中的各种不良点。

我们在前一段时间在irc上找到了它,修复是为了创建一个完全不同的flatten函数,它在cpython中更快,在pypy上更快

我不记得网址,如果OP提供

会很好

基本代码与

一致
def flatten(items, akk=None)
 if akk is None:
   akk  = []
 for item in items:
   if isinstance(item, list):
     flatten(item, akk)
   else:
     akk.append(item)

答案 1 :(得分:0)

答案而非评论以包含代码

很难理解代码的作用。确保它是正确的。稍后优化。你可以测试结果:

def flatten(lst, nonscalar_types=list):
    for x in lst:
        if isinstance(x, nonscalar_types):
            yield from flatten(x) # pep 380
        else:
            yield x # non-list type

实施例

print(sum(1 for _ in flatten(lol)))