#追記
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倍
の早さで定義できました。
結論