Pythonでdisってみた

以前dict()とリテラルで{}と書いた時の違いにコンストラクタ的なものが呼び出されないという記憶があったような無かったような気がしたけど、いい調べ方が思いつかなかったので放置してました。
が、今日[twitter:@methane]さんがエキスパートPythonプログラミングのリスト内包表記の解説補足をしていた記事をみてdisモジュール使ってdisればいいんじゃね?という事でdisって見ました。

disったコード

まず、空のディクショナリ生成のコード。
dict()

def dict_init():
    hoge = dict()

リテラル

def dict_literal():
    hoge = {}

で、disるコード。

dis.dis(dict1.dict_init)
dis.dis(dict2.dict_literal)

実行結果。

  4           0 LOAD_GLOBAL              0 (dict)
              3 CALL_FUNCTION            0
              6 STORE_FAST               0 (hoge)
              9 LOAD_CONST               0 (None)
             12 RETURN_VALUE        
  4           0 BUILD_MAP                0
              3 STORE_FAST               0 (hoge)
              6 LOAD_CONST               0 (None)
              9 RETURN_VALUE        

これの見方は左の列から、ソースの行番号、バイト数、ニモニック、参照変数インデックスとなるらしい。
で、結果を見るとやぱりdict()の方は何かの関数を呼んでいるみたいですね。
バイト数を単純に比較するだけならリテラルで書いた方が早いとうことも分かりました。

次に辞書に{'a': 'a'}が入るようなデータをリテラルとdict()バージョンの2つで見てみると結果は、

  4           0 LOAD_GLOBAL              0 (dict)
              3 LOAD_CONST               1 ('a')
              6 LOAD_CONST               1 ('a')
              9 CALL_FUNCTION          256
             12 STORE_FAST               0 (hoge)
             15 LOAD_CONST               0 (None)
             18 RETURN_VALUE        
  4           0 BUILD_MAP                1
              3 LOAD_CONST               1 ('a')
              6 LOAD_CONST               1 ('a')
              9 STORE_MAP           
             10 STORE_FAST               0 (hoge)
             13 LOAD_CONST               0 (None)
             16 RETURN_VALUE        

となった。
やっぱりリテラルで書いた方が早いですね。

ちなみに最後のRETURN_VALUEはNoneを返しているらしい。
return文を端折った場合は暗黙的にNoneを返すというのをどこかで見たんだけど詳しく覚えてない・・・

話を元に戻してdict()の中のCALL_FUNCTIONは何を呼んでいるのかというのはどの先はソースみるしかないなーということでそのうちまた書きます。