我正在查看提到的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"
更快?
答案 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}}的两个库调用。但是我实际上并没有对代码进行分析,因为我没有调试版本,所以我可能完全错了。