LoginSignup
7
7

More than 3 years have passed since last update.

【Python】動的に変数名を設定する方法と速度比較

Last updated at Posted at 2020-09-15

追記

locals()は関数内では正常に使用できないとのご指摘をいただきました(そもそも公式ドキュメントでは使うなとまで書いてある)。
使用する際はご注意を。

はじめに

ほとんど無いと思いますが、動的に変数名を設定したい場合があったりなかったりしちゃったりしちゃわなかったりするかもしれないので、その方法を調べてみました。(外部ファイルからデータを読み込んでそのままファイル名を変数名にしたい場合とか?)

2(+α)通りの方法を発見しましたので、紹介を兼ねて速度を比較したいと思います。

速度比較のルールと準備

ルール
・Jupyter Notebook上で%%timeitコマンドを用いて測定。
・ランダムな小文字アルファベット5文字を変数名とする。
・値として0から9までの整数が入ったリストを代入する。
・1,000回ループした平均を測定する。

準備
測定に影響しないように、予め変数名を用意する。


import random

chrs = [chr(i) for i in range(ord('a'), ord('z')+1)]
names = [''.join(random.sample(chrs, 10)) for i in range(10)]

方法1 exec()を使う

一番よく見かける方法。

%%timeit

for i in range(1000):
    exec(f'{names[i]} = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]')

結果
20.7 ms ± 75.7 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

方法2 locals() or globals()を使う

locals()globals()はそれぞれローカル変数、グローバル変数を管理している辞書という認識です(違ったらごめんなさい)。
通常のディクショナリ型と同様に、インデクサや.get()で値を取得、.update()で更新などといった操作ができます。

%%timeit
for i in range(1000):
    locals().update({f'{names[i]}':[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]})

結果
386 µs ± 24.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

少し方法を変えて

%%timeit
for i in range(1000):
    locals()[names[i]] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

結果
248 µs ± 387 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)

まとめ

exec()比で、
exec(): 1倍
locals().update(): 53倍
locals()[]: 83倍
の早さで定義できました。

結論

locals() (or globals())が早いよ。

7
7
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7