元组比Python中的列表更有效吗?

元组比Python中的列表更有效吗?

在实例化和检索元素时,元组和列表之间是否存在性能差异?



紫衣仙女
浏览 617回答 3
3回答

白猪掌柜的

该dis模块反汇编函数的字节代码,有助于查看元组和列表之间的区别。在这种情况下,您可以看到访问元素会生成相同的代码,但分配元组比分配列表要快得多。>>> def a():...     x=[1,2,3,4,5]...     y=x[2]...>>> def b():...     x=(1,2,3,4,5)...     y=x[2]...>>> import dis>>> dis.dis(a)  2           0 LOAD_CONST               1 (1)              3 LOAD_CONST               2 (2)              6 LOAD_CONST               3 (3)              9 LOAD_CONST               4 (4)             12 LOAD_CONST               5 (5)             15 BUILD_LIST               5             18 STORE_FAST               0 (x)  3          21 LOAD_FAST                0 (x)             24 LOAD_CONST               2 (2)             27 BINARY_SUBSCR             28 STORE_FAST               1 (y)             31 LOAD_CONST               0 (None)             34 RETURN_VALUE>>> dis.dis(b)  2           0 LOAD_CONST               6 ((1, 2, 3, 4, 5))              3 STORE_FAST               0 (x)  3           6 LOAD_FAST                0 (x)              9 LOAD_CONST               2 (2)             12 BINARY_SUBSCR             13 STORE_FAST               1 (y)             16 LOAD_CONST               0 (None)             19 RETURN_VALUE

慕雪6442864

通常,您可能希望元组稍快一些。但是你绝对应该测试你的特定情况(如果差异可能会影响你的程序的性能 - 记住“过早优化是所有邪恶的根源”)。Python使这很容易:timeit是你的朋友。$ python -m timeit "x=(1,2,3,4,5,6,7,8)"10000000 loops, best of 3: 0.0388 usec per loop $ python -m timeit "x=[1,2,3,4,5,6,7,8]"1000000 loops, best of 3: 0.363 usec per loop和...$ python -m timeit -s "x=(1,2,3,4,5,6,7,8)" "y=x[3]"10000000 loops, best of 3: 0.0938 usec per loop $ python -m timeit -s "x=[1,2,3,4,5,6,7,8]" "y=x[3]"10000000 loops, best of 3: 0.0649 usec per loop所以在这种情况下,元组的实例化速度几乎要快一个数量级,但是对于列表,项目访问实际上要快一些!因此,如果您创建了几个元组并多次访问它们,那么使用列表实际上可能会更快。当然,如果你想改变一个项目,列表肯定会更快,因为你需要创建一个全新的元组来改变它的一个项目(因为元组是不可变的)。

暮色呼如

摘要元组往往比几乎每个类别中的列表表现更好:1)元组可以不断折叠。2)可以重用元组而不是复制元组。3)元组是紧凑的,不会过度分配。4)元组直接引用它们的元素。元组可以不断折叠常量元组可以通过Python的窥孔优化器或AST优化器进行预先计算。另一方面,列表从头开始构建:    >>> from dis import dis    >>> dis(compile("(10, 'abc')", '', 'eval'))       1           0 LOAD_CONST               2 ((10, 'abc'))                   3 RETURN_VALUE        >>> dis(compile("[10, 'abc']", '', 'eval'))       1           0 LOAD_CONST               0 (10)                   3 LOAD_CONST               1 ('abc')                   6 BUILD_LIST               2                   9 RETURN_VALUE元组不需要复制运行tuple(some_tuple)立即返回。由于元组是不可变的,因此不必复制它们:>>> a = (10, 20, 30)>>> b = tuple(a)>>> a is bTrue相反,list(some_list)要求将所有数据复制到新列表:>>> a = [10, 20, 30]>>> b = list(a)>>> a is bFalse元组不会过度分配由于元组的大小是固定的,因此它可以比需要过度分配以使append()操作有效的列表更紧凑地存储。这为元组提供了一个很好的空间优势:>>> import sys>>> sys.getsizeof(tuple(iter(range(10))))128>>> sys.getsizeof(list(iter(range(10))))200以下是Objects / listobject.c中的注释,它解释了列表正在执行的操作:/* This over-allocates proportional to the list size, making room  * for additional growth.  The over-allocation is mild, but is  * enough to give linear-time amortized behavior over a long  * sequence of appends() in the presence of a poorly-performing  * system realloc().  * The growth pattern is:  0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...  * Note: new_allocated won't overflow because the largest possible value  *       is PY_SSIZE_T_MAX * (9 / 8) + 6 which always fits in a size_t.  */元组直接引用它们的元素对象的引用直接包含在元组对象中。相比之下,列表有一个额外的间接层指向外部指针数组。这为元组提供了索引查找和解包的小速度优势:$ python3.6 -m timeit -s 'a = (10, 20, 30)' 'a[1]'10000000 loops, best of 3: 0.0304 usec per loop $ python3.6 -m timeit -s 'a = [10, 20, 30]' 'a[1]'10000000 loops, best of 3: 0.0309 usec per loop $ python3.6 -m timeit -s 'a = (10, 20, 30)' 'x, y, z = a'10000000 loops, best of 3: 0.0249 usec per loop $ python3.6 -m timeit -s 'a = [10, 20, 30]' 'x, y, z = a'10000000 loops, best of 3: 0.0251 usec per loop以下是元组(10, 20)的存储方式:    typedef struct {         Py_ssize_t ob_refcnt;         struct _typeobject *ob_type;         Py_ssize_t ob_size;         PyObject *ob_item[2];     /* store a pointer to 10 and a pointer to 20 */     } PyTupleObject;以下是列表[10, 20]的存储方式:    PyObject arr[2];              /* store a pointer to 10 and a pointer to 20 */     typedef struct {         Py_ssize_t ob_refcnt;         struct _typeobject *ob_type;         Py_ssize_t ob_size;         PyObject **ob_item = arr; /* store a pointer to the two-pointer array */         Py_ssize_t allocated;     } PyListObject;请注意,元组对象直接包含两个数据指针,而列表对象有一个额外的间接层,用于保存两个数据指针的外部数组。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python