在python中创建列表的最佳和/或最快方法

时间:2013-12-28 16:15:53

标签: python list

在python中,据我所知,至少有3到4种方法可以创建和初始化给定大小的列表:

使用append进行简单循环:

my_list = []
for i in range(50):
    my_list.append(0)

使用+=进行简单循环:

my_list = []
for i in range(50):
    my_list += [0]

列表理解:

my_list = [0 for i in range(50)]

列表和整数乘法:

my_list = [0] * 50

在这些例子中,我不认为会有任何性能差异,因为这些列表只有50个元素,但如果我需要一个包含一百万个元素的列表呢?使用xrange会有什么改进吗?哪个是在python中创建和初始化列表的首选/最快方法?

4 个答案:

答案 0 :(得分:38)

让我们用timeit.timeit运行一些时间测试*:

>>> from timeit import timeit
>>>
>>> # Test 1
>>> test = """
... my_list = []
... for i in xrange(50):
...     my_list.append(0)
... """
>>> timeit(test)
22.384258893239178
>>>
>>> # Test 2
>>> test = """
... my_list = []
... for i in xrange(50):
...     my_list += [0]
... """
>>> timeit(test)
34.494779364416445
>>>
>>> # Test 3
>>> test = "my_list = [0 for i in xrange(50)]"
>>> timeit(test)
9.490926919482774
>>>
>>> # Test 4
>>> test = "my_list = [0] * 50"
>>> timeit(test)
1.5340533503559755
>>>

如上所示,到目前为止,最后一种方法是最快的。


但是,它应与不可变项(如整数)一起使用。这是因为它将创建一个列表,其中包含对同一项的引用。

以下是演示:

>>> lst = [[]] * 3
>>> lst
[[], [], []]
>>> # The ids of the items in `lst` are the same
>>> id(lst[0])
28734408
>>> id(lst[1])
28734408
>>> id(lst[2])
28734408
>>>

这种行为通常是不受欢迎的,可能会导致代码中的错误。

如果您有可变项(例如列表),那么您应该使用仍然非常快速的列表理解:

>>> lst = [[] for _ in xrange(3)]
>>> lst
[[], [], []]
>>> # The ids of the items in `lst` are different
>>> id(lst[0])
28796688
>>> id(lst[1])
28796648
>>> id(lst[2])
28736168
>>>

*注意:在所有测试中,我将range替换为xrange。由于后者返回迭代器,因此它应该总是比前者快。

答案 1 :(得分:17)

如果要查看列表n的长度的依赖关系:

Pure python

enter image description here

我测试了列表长度,最多n = 10000,行为保持不变。因此整数乘法方法是最快的差异。

numpy的

对于超过约300个元素的列表,您应该考虑numpy

enter image description here

基准代码:

import time

def timeit(f):

    def timed(*args, **kwargs):
        start = time.clock()
        for _ in range(100):
            f(*args, **kwargs)
        end = time.clock()
        return end - start
    return timed

@timeit
def append_loop(n):
    """Simple loop with append"""
    my_list = []
    for i in xrange(n):
        my_list.append(0)

@timeit
def add_loop(n):
    """Simple loop with +="""
    my_list = []
    for i in xrange(n):
        my_list += [0]

@timeit   
def list_comprehension(n):        
    """List comprehension"""
    my_list = [0 for i in xrange(n)]

@timeit
def integer_multiplication(n):
    """List and integer multiplication"""
    my_list = [0] * n


import numpy as np

@timeit
def numpy_array(n):
    my_list = np.zeros(n)


import pandas as pd 

df = pd.DataFrame([(integer_multiplication(n), numpy_array(n)) for n in range(1000)], 
                  columns=['Integer multiplication', 'Numpy array'])
df.plot()

要点here

答案 2 :(得分:1)

还有一种方法虽然听起来很奇怪,但在正确的情况下却很方便。如果你需要多次生成相同的列表(在我的情况下初始化roguelike pathfinding and related stuff的矩阵),你可以在列表中存储列表的副本,然后在需要时将其转换为列表。它比通过理解生成列表明显更快,并且与列表乘法不同,它适用于嵌套数据结构。

#  In class definition
def __init__(self):
    self.l = [[1000 for x in range(1000)] for y in range(1000)]
    self.t = tuple(self.l)

def some_method(self):
    self.l = list(self.t)
    self._do_fancy_computation()
    #  self.l is changed by this method

#  Later in code:
for a in range(10):
    obj.some_method()

Voila,在每次迭代中,您都可以立即获得相同列表的全新副本!

声明:

我没有任何想法为什么这么快,或者它是否适用于CPython 3.4以外的任何地方。

答案 3 :(得分:0)

如果要创建列表增量,即每次在范围参数中的列表参数中使用范围函数时加1,则如下所示,将终止值排除在外

list(range(10,20))
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

如果您希望每次在previuos元素上添加2时创建列表,请使用此功能,这是范围函数中的第三个值

list(range(10,20,2))
[10, 12, 14, 16, 18]

现在,您可以提供任何开始元素,结束元素和步骤,并更快,更轻松地创建许多列表。

谢谢..

学习愉快...:)