はじめに
ちわ
久々に Python を触って、ほえ~そっちが早いんだ、となったので久々に記事に
環境
Paiza.io の Python3 で確認
やりたいこと
以下のクラスのリストがあったとして、インスタンス変数ごと(a, b) ごとのリストを作成したい
クラスの数はとりあえず 1 万で
from random import random
class Klass:
def __init__(self):
self.a = random()
self.b = random()
klasses = [Klass() for _ in range(10_000)]
# a_list => [klasses[0].a, klasses[1].a, klasses[2].a, ...]
# b_list => [klasses[0].b, klasses[1].b, klasses[2].b, ...]
二つの書き方
ここで私は二つの書き方を思いつきました
append を使用する方法
def list_append(klasses):
a_list = []
b_list = []
for klass in klasses:
a_list.append(klass.a)
b_list.append(klass.b)
基本的な書き方
内包表記を使用する方法
def list_comprehensions(klasses):
a_list = [klass.a for klass in klasses]
b_list = [klass.b for klass in klasses]
みんな大好き内包表記
内包表記のほうが速いことは有名
でも二回 for 文回してるから append とどっちが速いんだ?
計測 & 結果
それぞれの関数を 100 回実行して平均・標準偏差を見てみる
from time import perf_counter
from statistics import mean, stdev
.
.
.
times = []
for _ in range(100):
start = perf_counter()
list_append(klasses)
times.append(perf_counter() - start)
print(f"append {mean(times)}, {stdev(times)}")
times = []
for _ in range(100):
start = perf_counter()
list_comprehensions(klasses)
times.append(perf_counter() - start)
print(f"comprehensions {mean(times)}, {stdev(times)}")
append 0.0011767360288649797, 2.8312350706089013e-05
comprehensions 0.0007572866510599851, 7.718037436949733e-06
ほえ~ for 文二回まわしてるのに内包表記のほうが、0.0004 秒早い結果に
インスタンス変数多くしてみたら?
じゃあ Klass のインスタンス変数増やして、作成するリスト増やしたら?
何となく 8 つに
これで内包表記は for を 8 回まわしていることになる
from time import perf_counter
from statistics import mean, stdev
from random import random
class Klass:
def __init__(self):
self.a = random()
self.b = random()
self.c = random()
self.d = random()
self.e = random()
self.f = random()
self.g = random()
self.h = random()
def list_append(klasses):
a_list = []
b_list = []
c_list = []
d_list = []
e_list = []
f_list = []
g_list = []
h_list = []
for klass in klasses:
a_list.append(klass.a)
b_list.append(klass.b)
c_list.append(klass.c)
d_list.append(klass.d)
e_list.append(klass.e)
f_list.append(klass.f)
g_list.append(klass.g)
h_list.append(klass.h)
def list_comprehensions(klasses):
a_list = [klass.a for klass in klasses]
b_list = [klass.b for klass in klasses]
c_list = [klass.c for klass in klasses]
d_list = [klass.d for klass in klasses]
e_list = [klass.e for klass in klasses]
f_list = [klass.f for klass in klasses]
g_list = [klass.g for klass in klasses]
h_list = [klass.h for klass in klasses]
.
. (計測のコード)
.
結果
append 0.004833733141422272, 0.00012474073760079379
comprehensions 0.003598997062072158, 1.9767736938103106e-05
それでも内包表記のほうが速い結果に
まとめ
処理時間を気にして for 文を一つにできないかとか考えがちですが
for 文内で何をしているかが大事ですね。(当たり前ですが)
余談
Paiza.io だとタイムアウトしてしまいましたが、クラスの数を 10 万にすると逆転しました
append 0.04548846199759282, 0.0013987592232240457
comprehensions 0.059213479993632065, 0.0009270777895173936
コード
from time import perf_counter
from statistics import mean, stdev
from random import random
class Klass:
def __init__(self):
self.a = random()
self.b = random()
self.c = random()
self.d = random()
self.e = random()
self.f = random()
self.g = random()
self.h = random()
def list_append(klasses):
a_list = []
b_list = []
c_list = []
d_list = []
e_list = []
f_list = []
g_list = []
h_list = []
for klass in klasses:
a_list.append(klass.a)
b_list.append(klass.b)
c_list.append(klass.c)
d_list.append(klass.d)
e_list.append(klass.e)
f_list.append(klass.f)
g_list.append(klass.g)
h_list.append(klass.h)
def list_comprehensions(klasses):
a_list = [klass.a for klass in klasses]
b_list = [klass.b for klass in klasses]
c_list = [klass.c for klass in klasses]
d_list = [klass.d for klass in klasses]
e_list = [klass.e for klass in klasses]
f_list = [klass.f for klass in klasses]
g_list = [klass.g for klass in klasses]
h_list = [klass.h for klass in klasses]
klasses = [Klass() for _ in range(10_000)]
times = []
for _ in range(100):
start = perf_counter()
list_append(klasses)
times.append(perf_counter() - start)
print(f"append {mean(times)}, {stdev(times)}")
times = []
for _ in range(100):
start = perf_counter()
list_comprehensions(klasses)
times.append(perf_counter() - start)
print(f"comprehensions {mean(times)}, {stdev(times)}")