我想知道为什么repr(int)
比str(int)
更快。使用以下代码段:
ROUNDS = 10000
def concat_strings_str():
return ''.join(map(str, range(ROUNDS)))
def concat_strings_repr():
return ''.join(map(repr, range(ROUNDS)))
%timeit concat_strings_str()
%timeit concat_strings_repr()
我得到了这些时间(python 3.5.2,但与2.7.12的结果非常相似):
1.9 ms ± 17.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
1.38 ms ± 9.07 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
如果我走在正确的道路上,the same function long_to_decimal_string
is getting called在引擎盖下方。
我错了什么或者我还缺少什么?
更新:
这可能与int
的{{1}}或__repr__
方法无关,但__str__
和repr()
之间存在差异,str()
和int.__str__
{1}}事实上相对较快:
int.__repr__
结果:
def concat_strings_str():
return ''.join([one.__str__() for one in range(ROUNDS)])
def concat_strings_repr():
return ''.join([one.__repr__() for one in range(ROUNDS)])
%timeit concat_strings_str()
%timeit concat_strings_repr()
答案 0 :(得分:33)
因为使用str(obj)
必须首先通过type.__call__
然后str.__new__
(create a new string)然后调用PyObject_Str
(make a string out of the object)的int.__str__
和最终,你链接的功能。
repr(obj)
对应的 builtin_repr
会直接调用PyObject_Repr
(get the object repr),然后调用使用与int.__str__
相同功能的int.__repr__
。
此外,他们通过call_function
(处理为调用生成的CALL_FUNCTION
opcode的函数)所采用的路径略微不同。
来自GitHub上的主分支(CPython 3.7):
str
通过_PyObject_FastCallKeywords
(调用type.__call__
的那个)。除了执行更多检查之外,还需要创建一个元组来保存位置参数(参见_PyStack_AsTuple
)。 repr
通过调用_PyCFunction_FastCallKeywords
的_PyMethodDef_RawFastCallKeywords
。 repr
也很幸运,因为它只接受一个参数(交换机将其引导到METH_0
中的_PyMethodDef_RawFastCallKeywords
个案例),因此无需创建元组,只需{{3} }。 根据您的更新说明,这不是int.__repr__
与int.__str__
的关系,它们毕竟是相同的功能;这完全取决于repr
和str
如何与他们联系。 str
只需要更努力地工作。
答案 1 :(得分:12)
我刚刚比较了3.5分支中的str
和repr
实现。
请参阅here。
答案 2 :(得分:8)
有几种可能性,因为负责str
和repr
返回的CPython函数略有不同。
但我想主要原因是str
是type
(一个类),而str.__new__
方法必须调用__str__
而repr
可以直接转到__repr__
。