読者です 読者をやめる 読者になる 読者になる

dictを使おう?

Python

dictを使おう、というお話に反応してみます。
dictの方が、クォートがなくてよい分、コードがすっきりとして見えるので、{}ではなくdictを使いたいとは思いますが、懸念点が一つあります。dictは関数呼び出しを行っている、ということです。


compilerを使って、ASTを確認してみます。

>>> import compiler
>>> compiler.parse("dict(spam=1)")
Module(None, Stmt([Discard(CallFunc(Name('dict'), [Keyword('spam', Const(1))], None, None))]))

dictを使った場合、キーワード引数での関数呼び出しとしてASTが生成されます。

>>> compiler.parse("{'spam':1}")
Module(None, Stmt([Discard(Dict([(Const('spam'), Const(1))]))]))

{}を使った場合、辞書表現としてASTが生成されます。
次にバイトコードを確認してましょう。

>>> def a(): return dict(spam=1)
... 
>>> def b(): return {'spam':1}
... 
>>> import dis
>>> dis.dis(a)
  1           0 LOAD_GLOBAL              0 (dict)
              3 LOAD_CONST               1 ('spam')
              6 LOAD_CONST               2 (1)
              9 CALL_FUNCTION          256
             12 RETURN_VALUE        
>>> dis.dis(b)
  1           0 BUILD_MAP                0
              3 DUP_TOP             
              4 LOAD_CONST               1 (1)
              7 ROT_TWO             
              8 LOAD_CONST               2 ('spam')
             11 STORE_SUBSCR        
             12 RETURN_VALUE

dictを使った方が、バイトコード自体は短くなりますが、関数呼び出しは非常にコストがかかるオペレーションなので、実行速度は{}の方が速いと予想します。
timeitで確かめてみます。

>>> from timeit import Timer
>>> Timer("a()", "from __main__ import a").timeit()
2.1254160404205322
>>> Timer("b()", "from __main__ import b").timeit()
1.4840729236602783

上がdict(spam=1)、下が{'spam':1}の結果です。Python2.4とPython2.5の両方で測定しましたが、{}の方が50%近く高速です。


まとめ。

  • dictを使いたいのになぁ。
  • 実行速度よりも可読性が優先されることはあるよ。
  • つーか、dictもバイトコードBUILD_MAPに変換されてほしい。