Last Updated: 2/6/2024, 5:44:57 AM
# 5. for 文かリスト内包表記か
リスト内包表記の方が速い
「4. for 文か while 文か」の結果でもそうでしたが、一般にリスト内包表記の方が速いそうです。 ここで、ランダムな整数のリストを生成することを考えます。
[random() for i in range(10)]
乱数の生成に random.randoint を使ってしまうと 今回作ったツールで funcscale.py で通らなくなってしまうので、 擬似乱数を生成するクロージャを用意しました。 これは 線形合同法 (opens new window) による擬似乱数生成器です。
昔、競プロの問題を解いていて、線形合同法を知らなくて、 これの規則性を見つける問題と勘違いして、辛い思いをしました笑
def linear_congruential_generators(a, x, b, m):
def random():
nonlocal x
x = (a * x + b) % m
return x
return random
random = linear_congruential_generators(48271, 8, 0, 2**31 - 1)
random() # 386168
random() # 1460846352
random() # 1741224500
# 5.1. 比較対象
次の通りです。for 文と for 文(属性参照の無いもの)とリスト内包表記の3つを比較しました。
def for_statement(i):
random = linear_congruential_generators(48271, 8, 0, 2**31 - 1)
lst = []
for _ in range(10**i):
lst.append(random())
return lst
def for_statement_speed_up(i):
random = linear_congruential_generators(48271, 8, 0, 2**31 - 1)
lst = []
append = lst.append
for _ in range(10**i):
append(random())
return lst
def for_statement_list_comprehension(i):
random = linear_congruential_generators(48271, 8, 0, 2**31 - 1)
return [random() for _ in range(10**i)]
# 5.2. 測定結果
測定結果は以下の通りです。
# Case 0
# (0, )
for_statement : 0.0015 [msec]
for_statement_speed_up : 0.0015 [msec]
for_statement_list_comprehension : 0.0015 [msec]
# Case 1
# (1, )
for_statement : 0.0060 [msec]
for_statement_speed_up : 0.0056 [msec]
for_statement_list_comprehension : 0.0055 [msec]
# Case 2
# (2, )
for_statement : 0.0436 [msec]
for_statement_speed_up : 0.0406 [msec]
for_statement_list_comprehension : 0.0396 [msec]
# Case 3
# (3, )
for_statement : 0.4258 [msec]
for_statement_speed_up : 0.3927 [msec]
for_statement_list_comprehension : 0.3898 [msec]
# Case 4
# (4, )
for_statement : 4.2091 [msec]
for_statement_speed_up : 4.2072 [msec]
for_statement_list_comprehension : 3.7209 [msec]
# Case 5
# (5, )
for_statement : 46.6584 [msec]
for_statement_speed_up : 42.4418 [msec]
for_statement_list_comprehension : 41.5389 [msec]
# Case 6
# (6, )
for_statement : 480.8355 [msec]
for_statement_speed_up : 457.6269 [msec]
for_statement_list_comprehension : 425.5688 [msec]
# ◯ なんでリスト内包表記は速いの?
メソッド呼び出しを避けることで、 リスト内包表記に近づいています。 リスト内包表記が速いことの要因の1つです。
実は、元のコードのオーバーヘッドの大半は、 append 属性の参照にあったという事になります。
Pythonの内包表記はなぜ速い? - DSAS開発者の部屋 (opens new window)
上記の記事では、バイトコードを比較しながらリスト内包表記と for 文を比較、 解説してくれている、大変ありがたい記事になります。