为什么 repr(int) 比 str(int) 快? [英] Why is repr(int) faster than str(int)?
问题描述
我想知道为什么 repr(int)
比 str(int)
快.使用以下代码片段:
I am wondering why repr(int)
is faster than str(int)
. With the following code snippet:
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 的结果非常相似):
I get these timings (python 3.5.2, but very similar results with 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)
如果我在正确的道路上,同样的功能long_to_decimal_string
在幕后被调用.
If I'm on the right path, the same function long_to_decimal_string
is getting called below the hood.
是我做错了什么还是我遗漏了什么?
Did I get something wrong or what else is going on that I am missing?
更新:这可能与 int
的 __repr__
或 __str__
方法无关,但与 repr()
和str()
,因为 int.__str__
和 int.__repr__
实际上相当快:
update:
This probably has nothing to with int
's __repr__
or __str__
methods but with the differences between repr()
and str()
, as int.__str__
and int.__repr__
are in fact comparably fast:
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()
结果:
2.02 ms ± 24.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.05 ms ± 7.07 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
推荐答案
因为使用 str(obj)
必须先经过 type.__call__
然后 str.__new__
(创建一个新字符串) 然后 PyObject_Str
(制作一个字符串对象之外),它调用 int.__str__
,最后,使用你链接的函数.
Because using str(obj)
must first go through type.__call__
then str.__new__
(create a new string) then PyObject_Str
(make a string out of the object) which invokes int.__str__
and, finally, uses the function you linked.
repr(obj)
,对应builtin_repr
,直接调用PyObject_Repr
(获取对象代表) 然后调用 int.__repr__
使用与int.__相同的函数.代码>.
repr(obj)
, which corresponds to builtin_repr
, directly calls PyObject_Repr
(get the object repr) which then calls int.__repr__
which uses the same function as int.__str__
.
此外,它们通过call_function
(处理CALL_FUNCTION
操作码(为调用生成)略有不同.
Additionally, the path they take through call_function
(the function that handles the CALL_FUNCTION
opcode that's generated for calls) is slightly different.
来自 GitHub (CPython 3.7) 上的 master 分支:
From the master branch on GitHub (CPython 3.7):
str
遍历_PyObject_FastCallKeywords
(即调用type.__call__
的那个).除了执行更多检查之外,这还需要创建一个元组来保存位置参数(参见_PyStack_AsTuple
).repr
遍历 <代码>_PyCFunction_FastCallKeywords 调用 _PyMethodDef_RawFastCallKeywords.repr
也很幸运,因为它只接受一个参数(开关将它引导到_PyMethodDef_RawFastCallKeywords
中的METH_0
案例),因此不需要创建一个元组,只需参数索引.
str
goes through_PyObject_FastCallKeywords
(which is the one that callstype.__call__
). Apart from performing more checks, this also needs to create a tuple to hold the positional arguments (see_PyStack_AsTuple
).repr
goes through_PyCFunction_FastCallKeywords
which calls_PyMethodDef_RawFastCallKeywords
.repr
is also lucky because, since it only accepts a single argument (the switch leads it to theMETH_0
case in_PyMethodDef_RawFastCallKeywords
) there's no need to create a tuple, just indexing of the args.
正如您的更新所述,这与 int.__repr__
与 int.__str__
无关,毕竟它们是相同的功能;这完全取决于 repr
和 str
如何到达它们.str
只需要更努力一点.
As your update states, this isn't about int.__repr__
vs int.__str__
, they are the same function after all; it's all about how repr
and str
reach them. str
just needs to work a bit harder.
这篇关于为什么 repr(int) 比 str(int) 快?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!