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

时间:2015-01-06 07:33:02

标签: python string-formatting

我正在查看提到的here示例,并且正在查看this example。我在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        

两个代码块都很相似,甚至反汇编程序的输出都是一样的,为什么"%s""%d"更快?

1 个答案:

答案 0 :(得分:6)

这在hacker news中进行了讨论,我只是格式化了@nikital的答案:

Objects/stringobject.c中的PyString_Format函数执行%运算符的格式设置。对于%s,它会调用_PyObject_Str,而str()会在对象上调用%d。对于formatint,它会调用str()(位于同一文件中)。

整数的int_to_decimal_string实施位于(Objects/intobject.c)的do { *--p = '0' + (char)(absn % 10); absn /= 10; } while (absn); ,并且非常简单:

formatint

PyOS_snprintf(fmt, sizeof(fmt), "%s%%%s.%dl%c", sign, (flags&F_ALT) ? "#" : "", prec, type); // ... PyOS_snprintf(buf, buflen, fmt, -x); 的代码更复杂,它包含对本机snprintf的两次调用:

snprintf

原生%d更重,因为它处理精度,零填充和类似的东西。

我相信这就是%s速度慢的原因。 %d是一个直接的"除以10和减去"循环,而sprintf是对完整版{{1}}的两个库调用。但是我实际上并没有对代码进行分析,因为我没有调试版本,所以我可能完全错了。