为什么%s在python中对于整数替换比%d更快?

mu *_*u 無 8 python string-formatting

我正在阅读这里提到的例子,我正在看这个例子.我在ipython上运行了一个示例示例,结果是一致的,即"%d"慢于"%s":

In [1]: def m1():
   ...:     return "%d" % (2*3/5)

In [2]: def m2():
   ...:     return "%s" % (2*3/5)

In [4]: %timeit m1()
1000000 loops, best of 3: 529 ns per loop

In [5]: %timeit m2()
1000000 loops, best of 3: 192 ns per loop

In [6]: from dis import dis

In [7]: dis(m1)
  2           0 LOAD_CONST               1 ('%d')
              3 LOAD_CONST               5 (6)
              6 LOAD_CONST               4 (5)
              9 BINARY_DIVIDE       
             10 BINARY_MODULO       
             11 RETURN_VALUE        

In [9]: dis(m2)
  2           0 LOAD_CONST               1 ('%s')
              3 LOAD_CONST               5 (6)
              6 LOAD_CONST               4 (5)
              9 BINARY_DIVIDE       
             10 BINARY_MODULO       
             11 RETURN_VALUE        
Run Code Online (Sandbox Code Playgroud)

两个代码块都很相似,甚至反汇编器的输出都是一样的,为什么"%s"速度比"%d"

ely*_*ase 6

这是在黑客新闻中讨论过的,我只是为了SO格式化@nikital答案:

该功能PyString_FormatObjects/stringobject.c做为格式化%操作.因为%s它调用_PyObject_Str反过来调用str()对象.对于%d它的调用formatint(位于同一个文件中).

str()ints 的实现在int_to_decimal_stringin(Objects/intobject.c)中,它非常简单:

do {
    *--p = '0' + (char)(absn % 10);
    absn /= 10;
} while (absn);
Run Code Online (Sandbox Code Playgroud)

代码formatint更复杂,它包含对本机snprintf的两次调用:

PyOS_snprintf(fmt, sizeof(fmt), "%s%%%s.%dl%c",
              sign, (flags&F_ALT) ? "#" : "",
              prec, type);
// ...
PyOS_snprintf(buf, buflen, fmt, -x);
Run Code Online (Sandbox Code Playgroud)

本机snprintf更重,因为它处理精度,零填充和类似的东西.

我相信这就是为什么%d慢一点.%s是一个直接的"除以10和减去"循环,而%d两个库调用完全成熟sprintf.但是我实际上没有对代码进行概要分析,因为我没有调试版本,所以我可能完全错了.