假設我們需要將單個數字附加1到 array a。
在 Python 中,我們有 5 種明顯的方法:
a.append(1)a = [1]a = 1,a.extend((1,))a.extend([1])
讓我們用 來衡量它timeit:
from timeit import timeit
print(timeit("a.append(1)", "a = []", number=10_000_000))
print(timeit("a = [1]", "a = []", number=10_000_000))
print(timeit("a = 1,", "a = []", number=10_000_000))
print(timeit("a.extend((1,))", "a = []", number=10_000_000))
print(timeit("a.extend([1])", "a = []", number=10_000_000))
這是控制臺的輸出:
5.05412472199896
5.869792026000141
3.1280645619990537
4.988895307998973
8.05588494499898
為什么第三個比其他更有效?
uj5u.com熱心網友回復:
元組的創建(1,)被編譯器優化掉了。另一方面,總是創建串列。看著dis.dis
>>> import dis
>>> dis.dis('a.extend((1,))')
1 0 LOAD_NAME 0 (a)
2 LOAD_METHOD 1 (extend)
4 LOAD_CONST 0 ((1,))
6 CALL_METHOD 1
8 RETURN_VALUE
>>> dis.dis('a.extend([1])')
1 0 LOAD_NAME 0 (a)
2 LOAD_METHOD 1 (extend)
4 LOAD_CONST 0 (1)
6 BUILD_LIST 1
8 CALL_METHOD 1
10 RETURN_VALUE
請注意,它需要更少的位元組碼指令,并且只執行LOAD_CONSTon (1,)。另一方面,對于串列,BUILD_LIST呼叫(帶有LOAD_CONSTfor 1)。
請注意,您可以在代碼物件上訪問這些常量:
>>> code = compile('a.extend((1,))', '', 'eval')
>>> code
<code object <module> at 0x10e91e0e0, file "", line 1>
>>> code.co_consts
((1,),)
最后,關于為什么 =比 快.extend,好吧,如果你再看一下位元組碼:
>>> dis.dis('a = b')
1 0 LOAD_NAME 0 (a)
2 LOAD_NAME 1 (b)
4 INPLACE_ADD
6 STORE_NAME 0 (a)
8 LOAD_CONST 0 (None)
10 RETURN_VALUE
>>> dis.dis('a.extend(b)')
1 0 LOAD_NAME 0 (a)
2 LOAD_METHOD 1 (extend)
4 LOAD_NAME 2 (b)
6 CALL_METHOD 1
8 RETURN_VALUE
你會注意到.extend,它需要首先決議方法(這需要額外的時間)。另一方面,使用運算子有它自己的位元組碼:INPLACE_ADD所以一切都被推到那個 C 層(另外,魔術方法跳過實體名稱空間和一堆 hooplah 并直接在類上查找)。
uj5u.com熱心網友回復:
好的,總結一下,@juanpa.arrivillaga、@Samwise 和 @Barmar 提到的內容:
a = (1, )等同于a.__iadd__((1, ))但沒有加載方法。如果我們看dis:
>>> dis.dis("a.__iadd__((1,))")
1 0 LOAD_NAME 0 (a)
2 LOAD_METHOD 1 (__iadd__)
4 LOAD_CONST 0 ((1,))
6 CALL_METHOD 1
8 RETURN_VALUE
>>> dis.dis("a = (1, )")
1 0 LOAD_NAME 0 (a)
2 LOAD_CONST 0 ((1,))
4 INPLACE_ADD
6 STORE_NAME 0 (a)
8 LOAD_CONST 1 (None)
10 RETURN_VALUE
>>> dis.dis("a.append(1)")
1 0 LOAD_NAME 0 (a)
2 LOAD_METHOD 1 (append)
4 LOAD_CONST 0 (1)
6 CALL_METHOD 1
8 RETURN_VALUE
您可以看到,在第一種和第三種情況下,我們需要LOAD_METHOD在呼叫之前使用,這是最資源平均的部分,同時 =具有直接反匯編程式
順便說一句,第一個案例比前五個更糟糕,并且8.292503296999712準時到達
uj5u.com熱心網友回復:
元組和串列之間的差異完全是由于創建每個所需的時間不同。這很容易通過自己定時創建串列/元組來驗證,并通過 =獨立于添加物件的創建定時操作來驗證:
>>> timeit("b = [1]", number=10_000_000)
0.447727799997665
>>> timeit("b = (1,)", number=10_000_000)
0.17419059993699193
>>> timeit("a = b", "a, b = [], [1]", number=10_000_000)
0.5244328000117093
>>> timeit("a = b", "a, b = [], (1,)", number=10_000_000)
0.5320590999908745
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/427608.html
上一篇:在串列串列中搜索2個條件
