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

eca*_*ver 30 python list

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

简单循环append:

my_list = []
for i in range(50):
    my_list.append(0)
Run Code Online (Sandbox Code Playgroud)

简单循环+=:

my_list = []
for i in range(50):
    my_list += [0]
Run Code Online (Sandbox Code Playgroud)

列表理解:

my_list = [0 for i in range(50)]
Run Code Online (Sandbox Code Playgroud)

列表和整数乘法:

my_list = [0] * 50
Run Code Online (Sandbox Code Playgroud)

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

iCo*_*dez 40

让我们运行一些时间测试*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
>>>
Run Code Online (Sandbox Code Playgroud)

如您所见,最后一种方法是迄今为止最快的方法.


但是,应该用一成不变的物品(如整数)使用.这是因为它将创建一个列表,其中包含对同一项的引用.

以下是演示:

>>> 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
>>>
Run Code Online (Sandbox Code Playgroud)

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

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

>>> 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
>>>
Run Code Online (Sandbox Code Playgroud)

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

  • @PascalvKooten Python 3 中的`range` 与Python 2 中的`xrange` 类似。它们都返回一个迭代器,而不是像Python 2 的`range` 那样创建一个列表。 (2认同)

ely*_*ase 19

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

纯蟒蛇

在此输入图像描述

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

NumPy的

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

在此输入图像描述

基准代码:

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()
Run Code Online (Sandbox Code Playgroud)

点击这里.

  • 是什么导致两种方法的突然飙升〜500? (4认同)
  • 我想知道同样的事情.它似乎是随机波动,没有特别的原因,也许PC正忙于在那个特定时刻做其他事情.如果我重复基准测试,峰值会消失或出现在列表长度的不同值上. (2认同)