Pythonでのstrのパフォーマンス


88

Pythonコードの一部(python 2.6最大3.2)をプロファイリングしてstrいるときに、オブジェクト(私の場合は整数)を文字列に変換する方法が、文字列の書式設定を使用するよりもほぼ1桁遅いことを発見しました 。

これがベンチマークです

>>> from timeit import Timer
>>> Timer('str(100000)').timeit()
0.3145311339386332
>>> Timer('"%s"%100000').timeit()
0.03803517023435887

なぜこれが当てはまるのか誰かが知っていますか?私は何かが足りないのですか?


2
そしてどう'{}'.format(100000)
2012年

これは最も遅いですが、最も柔軟性があります。
Luca Sbardella 2012年

回答:


106

'%s' % 100000 コンパイラによって評価され、実行時の定数と同等です。

>>> import dis
>>> dis.dis(lambda: str(100000))
  8           0 LOAD_GLOBAL              0 (str)
              3 LOAD_CONST               1 (100000)
              6 CALL_FUNCTION            1
              9 RETURN_VALUE        
>>> dis.dis(lambda: '%s' % 100000)
  9           0 LOAD_CONST               3 ('100000')
              3 RETURN_VALUE        

%ランタイム式を使用すると、(大幅に)次よりも速くなりませんstr

>>> Timer('str(x)', 'x=100').timeit()
0.25641703605651855
>>> Timer('"%s" % x', 'x=100').timeit()
0.2169809341430664

str@DietrichEppが言ったように、それでも少し遅いことに注意してください。これは、単一の即時バイトコードにコンパイルするときに、strルックアップと関数呼び出しの操作が含まれるため%です。

>>> dis.dis(lambda x: str(x))
  9           0 LOAD_GLOBAL              0 (str)
              3 LOAD_FAST                0 (x)
              6 CALL_FUNCTION            1
              9 RETURN_VALUE        
>>> dis.dis(lambda x: '%s' % x)
 10           0 LOAD_CONST               1 ('%s')
              3 LOAD_FAST                0 (x)
              6 BINARY_MODULO       
              7 RETURN_VALUE        

もちろん、上記は私がテストしたシステム(CPython 2.7)にも当てはまります。他の実装は異なる場合があります。


確かにこれが理由のように見えます。私は自分で試したところ、文字列の書式設定はstr。よりも約5%高速です。ご回答ありがとうございます。どこでもコードを変更する理由はありません:
Luca Sbardella 2012年

2
さらに詳しく説明strすると、は文字列型以外にリバウンドできる名前ですが、文字列の書式設定(つまり、str.__mod__メソッド)を置き換えることはできません。これにより、コンパイラーは最適化を実行できます。コンパイラーは最適化の方法ではあまり機能しませんが、
想像

4
...そしてここで学ぶべき教訓は次のとおりです:これらのようなテストではリテラルを決して使用しないでください!
UncleZeiv 2012年

この特定のブログエントリはあなたに興味があるかもしれません:skymind.com/~ocrow/python_string。これには、上記で提供したものと同様のさまざまな文字列連結方法のベンチマークのチャートが含まれています。
アーロンニュートン

14

頭に浮かぶ理由の1つstr(100000)は、グローバルルックアップを含むが、"%s"%100000含まないという事実です。str世界はグローバルスコープで検索する必要があります。これは全体の違いを説明するものではありません。

>>> Timer('str(100000)').timeit()
0.2941889762878418
>>> Timer('x(100000)', 'x=str').timeit()
0.24904918670654297

thg435で指摘されているように

>>> Timer('"%s"%100000',).timeit()
0.034214019775390625
>>> Timer('"%s"%x','x=100000').timeit()
0.2940788269042969
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.