元组是否比Python中的列表更有效?
元组和列表在元素的实例化和检索时是否有任何性能差异?
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
一般来说,你可能期望元组稍微快一点。 但是,您应该明确地testing您的具体情况(如果差异可能会影响程序的性能 – 请记住“过早优化是万恶之源”)。
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
所以在这种情况下,对于元组来说,实例化几乎要快一个数量级,但是对于列表来说,项访问实际上更快一些! 所以如果你创build了几个元组并且多次访问它们,实际上使用列表可能会更快。
当然,如果你想改变一个项目,这个列表一定会更快,因为你需要创build一个新的元组来改变它的一个项目(因为元组是不可变的)。
元组和列表之间在元素的实例化和检索时有几个性能差异:
-
包含不可变条目的元组可以通过Python的窥视优化器优化为常量。 另一方面,列表从头开始构build:
>>> 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
-
在内部,元组的存储效率要比列表高一点,元组的访问速度也可以稍微快一些。
这里是元组
(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;
请注意,元组对象直接合并两个数据指针,而列表对象具有一个附加层间接指向包含两个数据指针的外部数组。
元组是不可改变的,它们的记忆效率更高。 为了提高效率,列出了过度分配内存以允许不经常重新分配的附加内容。 所以,如果你想迭代你的代码中的一个常量值序列(例如for direction in 'up', 'right', 'down', 'left':
):元组是首选的,因为这些元组是预先计算的在编译时。
访问速度应该是相同的(它们都被存储在内存中的连续数组)。
但是,当处理可变数据时, alist.append(item)
比atuple+= (item,)
更atuple+= (item,)
。 请记住,元组旨在被视为没有字段名称的logging。
如果列表或元组中的所有项都是相同types的,则还应该考虑标准库中的array
模块。 它可以更快,占用更less的内存。
元组应该更有效一些,因为它比列表更快,因为它们是不变的。