89

在分析一段 python 代码(python 2.6最多3.2)时,我发现 str将对象(在我的例子中是整数)转换为字符串的方法几乎比使用字符串格式化慢一个数量级。

这是基准

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

有谁知道为什么会这样?我错过了什么吗?

4

2 回答 2

108

'%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),以上是正确的;其他实现可能会有所不同。

于 2012-05-10T08:43:28.690 回答
15

想到的一个原因是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
于 2012-05-10T08:41:42.593 回答