元组构造函数vs列表comp

时间:2013-04-12 14:04:34

标签: python list tuples

说我有一个清单

a = (3, 2, 9, 4)

我想在每个数字中添加一个并存储结果,(我之后不需要操纵结果),我的第一个想法就是:

[x + 1 for x in a]

但是怎么样:

tuple(x + 1 for x in a)

元组意味着更快吧?如果我不需要在此代码更高效后更改结果?它是如何工作的,tuple构造函数是否必须从生成器表达式中创建一个列表以提前知道大小?提前感谢您的任何解释。

3 个答案:

答案 0 :(得分:5)

只是timeit()

In : a = (3, 2, 9, 4)

In : f1 = lambda: [x + 1 for x in a]

In : f2 = lambda: tuple(x + 1 for x in a)

In : timeit.timeit(f1)
Out: 0.595026969909668

In : timeit.timeit(f2)
Out: 2.360887050628662

所以看起来元组构造函数变体花了大约四倍的时间,我想是因为列表推导相当优化(在cpython中)。

但让我们仔细看看:

In : f3 = lambda: list(x + 1 for x in a)

In : timeit.timeit(f3)
Out: 2.5421998500823975

因此这与元组构造大致相同,这表明性能损失在于生成器表达式开销。 (我们可以排除列表/元组结构,见下面的编辑)

它甚至比列表的map()慢两倍:

In : inc = partial(operator.add,1)

In : f4 = lambda:map(inc, a)

In : timeit.timeit(f4)
Out: 1.2346529960632324

我认为这实际上归结为(cpython)实现细节,所以不要依赖于此。 无论如何 - 不要担心性能,它只是2-4的因素,使用最好阅读的方法。

如果您确实遇到了性能瓶颈,请在之后调查并优化它们。而且我敢打赌,列表操作中的因子4将是您遇到问题的最小因素。

修改 有人提到“元组”的查找成本可能会导致速度减慢,但事实并非如此:

In : f5 = lambda: tuple([x + 1 for x in a])

In : timeit.timeit(f5)
Out: 0.7900090217590332

所以我猜它确实是生成器表达式开销会降低速度。

答案 1 :(得分:2)

dis模块可以让您了解代码如何在内部执行...

dis.dis(lambda a: [x + 1 for x in a])收益......

  1           0 BUILD_LIST               0
              3 LOAD_FAST                0 (a)
              6 GET_ITER
        >>    7 FOR_ITER                16 (to 26)
             10 STORE_FAST               1 (x)
             13 LOAD_FAST                1 (x)
             16 LOAD_CONST               1 (1)
             19 BINARY_ADD
             20 LIST_APPEND              2
             23 JUMP_ABSOLUTE            7
        >>   26 RETURN_VALUE

......和dis.dis(lambda a: tuple(x + 1 for x in a))收益......

  1           0 LOAD_GLOBAL              0 (tuple)
              3 LOAD_CONST               1 (<code object <genexpr> at 0x7f62e9eda930, file "<stdin>", line 1>)
              6 MAKE_FUNCTION            0
              9 LOAD_FAST                0 (a)
             12 GET_ITER
             13 CALL_FUNCTION            1
             16 CALL_FUNCTION            1
             19 RETURN_VALUE

...但你可能无法从中推断出太多。如果您想知道哪个更快,请查看timeit模块。

答案 2 :(得分:0)

在大多数情况下,元组和列表之间的效率确实无关紧要。如果您真的关心它,可以使用timeit进行测试。

元组和列表之间最重要的区别是元组是不可变的,列表是可以替换的。 这意味着您可以更改列表的值,但不能使用元组。你可以散列元组但不能用列表来做。 例如

k_tuple = ('a', 'b')
k_list = ['a', 'b']
d = {}
d[k_tuple] = 'c' # It is ok
d[k_list] = 'c' #It raise exception.

更重要的是,当list作为函数的参数时,它是通过引用分配的。当元组作为函数的参数时,它由值分配。