3 回答

TA貢獻(xiàn)1893條經(jīng)驗(yàn) 獲得超10個(gè)贊
該dis
模塊反匯編函數(shù)的字節(jié)代碼,有助于查看元組和列表之間的區(qū)別。
在這種情況下,您可以看到訪問(wèn)元素會(huì)生成相同的代碼,但分配元組比分配列表要快得多。
>>> 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

TA貢獻(xiàn)1812條經(jīng)驗(yàn) 獲得超5個(gè)贊
通常,您可能希望元組稍快一些。但是你絕對(duì)應(yīng)該測(cè)試你的特定情況(如果差異可能會(huì)影響你的程序的性能 - 記住“過(guò)早優(yōu)化是所有邪惡的根源”)。
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
所以在這種情況下,元組的實(shí)例化速度幾乎要快一個(gè)數(shù)量級(jí),但是對(duì)于列表,項(xiàng)目訪問(wèn)實(shí)際上要快一些!因此,如果您創(chuàng)建了幾個(gè)元組并多次訪問(wèn)它們,那么使用列表實(shí)際上可能會(huì)更快。
當(dāng)然,如果你想改變一個(gè)項(xiàng)目,列表肯定會(huì)更快,因?yàn)槟阈枰獎(jiǎng)?chuàng)建一個(gè)全新的元組來(lái)改變它的一個(gè)項(xiàng)目(因?yàn)樵M是不可變的)。

TA貢獻(xiàn)1853條經(jīng)驗(yàn) 獲得超9個(gè)贊
摘要
元組往往比幾乎每個(gè)類別中的列表表現(xiàn)更好:
1)元組可以不斷折疊。
2)可以重用元組而不是復(fù)制元組。
3)元組是緊湊的,不會(huì)過(guò)度分配。
4)元組直接引用它們的元素。
元組可以不斷折疊
常量元組可以通過(guò)Python的窺孔優(yōu)化器或AST優(yōu)化器進(jìn)行預(yù)先計(jì)算。另一方面,列表從頭開始構(gòu)建:
>>> 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
元組不需要復(fù)制
運(yùn)行tuple(some_tuple)
立即返回。由于元組是不可變的,因此不必復(fù)制它們:
>>> a = (10, 20, 30)>>> b = tuple(a)>>> a is bTrue
相反,list(some_list)
要求將所有數(shù)據(jù)復(fù)制到新列表:
>>> a = [10, 20, 30]>>> b = list(a)>>> a is bFalse
元組不會(huì)過(guò)度分配
由于元組的大小是固定的,因此它可以比需要過(guò)度分配以使append()操作有效的列表更緊湊地存儲(chǔ)。
這為元組提供了一個(gè)很好的空間優(yōu)勢(shì):
>>> import sys>>> sys.getsizeof(tuple(iter(range(10))))128>>> sys.getsizeof(list(iter(range(10))))200
以下是Objects / listobject.c中的注釋,它解釋了列表正在執(zhí)行的操作:
/* 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. */
元組直接引用它們的元素
對(duì)象的引用直接包含在元組對(duì)象中。相比之下,列表有一個(gè)額外的間接層指向外部指針數(shù)組。
這為元組提供了索引查找和解包的小速度優(yōu)勢(shì):
$ 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)
的存儲(chǔ)方式:
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]
的存儲(chǔ)方式:
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;
請(qǐng)注意,元組對(duì)象直接包含兩個(gè)數(shù)據(jù)指針,而列表對(duì)象有一個(gè)額外的間接層,用于保存兩個(gè)數(shù)據(jù)指針的外部數(shù)組。
添加回答
舉報(bào)