電話或許有些解釋。這些被作爲單獨的字節代碼執行:
>>> import dis
>>> dis.dis(compile('s.__contains__(i)', '<>', 'exec'))
1 0 LOAD_NAME 0 (s)
3 LOAD_ATTR 1 (__contains__)
6 LOAD_NAME 2 (i)
9 CALL_FUNCTION 1
12 POP_TOP
13 LOAD_CONST 0 (None)
16 RETURN_VALUE
LOAD_ATTR
加載__contains__
屬性,CALL_FUNCTION
然後執行該方法。
使用i in s
只需一個字節碼:
>>> dis.dis(compile('i in s', '<>', 'exec'))
1 0 LOAD_NAME 0 (i)
3 LOAD_NAME 1 (s)
6 COMPARE_OP 6 (in)
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
這裏COMPARE_OP
做所有的工作。
在C中,然後,查找__contains__
插槽(或更確切地說,它的C等價物)並調用它更快。
請注意,比較Python中的兩種方法時,使用timeit
module而不是UNIX time
命令要好得多;它會嘗試消除環境因素和重複測試你:
>>> import timeit, random
>>> testset = {random.randrange(50000) for _ in xrange(1000)}
>>> tests = [random.randrange(5000) for _ in xrange(500)]
>>> timeit.timeit('for i in tests: i in s',
... 'from __main__ import testset as s, tests',
... number=100000)
2.5375568866729736
>>> timeit.timeit('for i in tests: s.__contains__(i)',
... 'from __main__ import testset as s, tests',
... number=100000)
4.208703994750977
使用__contains__
是由一些距離比較慢。
對random.randrange()的調用使您的timeit測試淹沒了十倍。 – msw 2014-09-02 15:37:04
@msw:'random.randrange()'調用*不會在測試*之間變化。我們在這裏比較相對時間。如果您願意,您可以預先生成這些隨機數字,但不會改變結果。 – 2014-09-02 15:43:31
[結果是相反的](http://nbviewer.ipython.org/gist/zed/af2b99517838061ec7b9)在我的機器上 – jfs 2014-09-02 15:51:50