20

Pythonを使用して作成したコードは次のとおりです。

from math import sqrt
abundant_list = []

for i in range(12,28123+1):
    dividor_list = [1]
    for j in range(2, int(sqrt(i))+1):
        if i%j == 0:
            dividor_list.extend([i/j,j])
    if sum(dividor_list) > i:
        abundant_list.append(i)

print abundant_list

ご覧のとおり、コードは実際に可能な限り効率的にしようとしています。

list.append2回使用しても1回だけ使用しても違いはありますlist.extendか?私はそれが小さな違いかもしれないことを知っています、しかし私は本当にそれを知りたいです:)

4

3 に答える 3

25
import timeit

def append2x(foo):
    foo.append(1)
    foo.append(1)

def extend_lst(foo):
    foo.extend([1,1])

def extend_tup(foo):
    foo.extend((1,1))


l1 = []
l2 = []
l3 = []

print timeit.timeit('append2x(l1)',setup = 'from __main__ import append2x,l1')
print timeit.timeit('extend_lst(l2)',setup = 'from __main__ import extend_lst,l2')
print timeit.timeit('extend_tup(l3)',setup = 'from __main__ import extend_tup,l3')

これが簡単なベンチマークです。私の結果 (os-X、10.5.8、core2duo、FWIW):

0.520906925201  #append
0.602569103241  #extend-list
0.357008934021  #extend-tuple

そして、私のLinuxボックス(Ubuntu、x86-64コアi7)の結果の同じ順序:

0.307395935059  #append
0.319436073303  #extend-list
0.238317012787  #extend-tuple

私にとって、これは のextend方が より速いと言っていますappendが、 を作成するのは を作成するよりもlist比較的高価ですtuple


編集

以下のコメントで指摘されているように、タプルの不変性により、インタープリターはタプルの作成を最適化できます (タプルを一度作成すると、それを何度も再利用します)。コードを次のように変更すると:

def extend_lst(foo):  
    v = 1
    foo.extend([v,v]) 

def extend_tup(foo):
    v = 1
    foo.extend((v,v))

タイミングはほぼ同じです。

0.297003984451  #append
0.344678163528  #extend-list
0.292304992676  #extend-tuple

tupleそれでも一貫してリストバージョンよりも優れておりappend、私が行ったすべての試行でバージョンをほとんど上回っていません.

これから私が取っていることの 1 つは、すべてのリテラルで構成されるオブジェクトを反復処理する場合は、 atupleよりも a を選択することlistです。完全にリテラルで構成されていない場合は、listまたはを選択しても問題ありませんtuple

于 2013-01-21T19:56:31.787 に答える
20

この質問に対する答えは、反復ごとに追加されるリスト/タプルのサイズが小さいことにかかっていることも指摘しておく価値があります。より大きなリストの場合、extend が明らかに優れています (また、リストとタプルは違いがありません)。mgilsonanswerから始めて、2 項目ではなく 600 項目のコレクションの動作を確認しました: append を 600 回呼び出すextend()と、手動で定義されたリスト/タプル (つまり[v,v,v,v,v,v,v...])を使用する場合の 8 倍の時間がかかります。

42.4969689846
5.45146393776
5.38034892082

この 5 秒の大部分は、実際にはリスト/タプルの作成です。電話の前に準備することでtimeit、延長の時間が短縮されます

1.42491698265
0.657584905624

それぞれリストとタプル。

より現実的な (そして公平な) ケースとして、関数呼び出し内でデータを動的に生成できます。

import timeit

def append_loop(foo, reps):
    for i in range(reps):
        foo.append(i)

def append_comp(foo, reps):
    [foo.append(i) for i in range(reps)]

def extend_lst(foo, reps):
    foo.extend([i for i in range(reps)])

def extend_tup(foo, reps):
    foo.extend((i for i in range(reps)))

repetitions = 600

print timeit.timeit('append_loop([], repetitions)', setup='from __main__ import append_loop, repetitions')
print timeit.timeit('append_comp([], repetitions)', setup='from __main__ import append_comp, repetitions')
print timeit.timeit('extend_lst([], repetitions)', setup='from __main__ import extend_lst, repetitions')
print timeit.timeit('extend_tup([], repetitions)', setup='from __main__ import extend_tup, repetitions')

(Append は、for ループとリスト内包表記の両方を介して実装され、ループの 2 つの方法の間の効率の違いを取り除きます。)

タイミングは次のとおりです。

53.8211231232
57.1711571217
19.8829259872
28.5986201763

ご覧のとおり、リスト内包表記による拡張は、追加よりも 2 倍以上高速です。また、タプル内包表記はリスト内包表記よりも著しく遅く見え、append_comp不必要なリスト作成オーバーヘッドを導入するだけです。

于 2015-12-03T21:51:20.770 に答える
0

それらはまったく同じ時間かかります。

コードにかかる時間は次のとおりです。

dividor_list.extend([i/j,j])

>>> 
0:00:00.410000
>>> 
0:00:00.383000
>>> 
0:00:00.389000

dividor_list.append(i/j); dividor_list.append(j)

>>> 
0:00:00.400000
>>> 
0:00:00.390000
>>> 
0:00:00.381000
于 2013-01-21T19:59:01.700 に答える