複数 List 作成時 for 一回 append より、内包表記で複数 for のほうが速いんだ

# はじめに

ちわ

久々に Python を触って、ほえ～そっちが早いんだ、となったので久々に記事に


# 環境

[Paiza.io](https://paiza.io/ja/projects/new) の Python3 で確認


# やりたいこと

以下のクラスのリストがあったとして、インスタンス変数ごと（a, b） ごとのリストを作成したい
クラスの数はとりあえず 1 万で

```python
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 を使用する方法

```python
def list_append(klasses):
    a_list = []
    b_list = []
    for klass in klasses:
        a_list.append(klass.a)
        b_list.append(klass.b)
```

基本的な書き方

### 内包表記を使用する方法


```python
def list_comprehensions(klasses):
    a_list = [klass.a for klass in klasses]
    b_list = [klass.b for klass in klasses]
```

みんな大好き内包表記

内包表記のほうが速いことは有名
でも二回 for 文回してるから append とどっちが速いんだ？


# 計測 ＆ 結果

それぞれの関数を 100 回実行して平均・標準偏差を見てみる

```python
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 回まわしていることになる

```python
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
```


# コード

```python
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)}")

```