'{0}'.format() 使用 IPython %timeit 比 str() 和 '{}'.format() 快,否则使用纯 Python
'{0}'.format() is faster than str() and '{}'.format() using IPython %timeit and otherwise using pure Python
所以这是一个 CPython 的东西,不太确定它与其他实现有相同的行为。
但是 '{0}'.format()
比 str()
和 '{}'.format()
快。我正在发布 Python 3.5.2 的结果,但是,我尝试使用 Python 2.7.12 和趋势是一样的。
%timeit q=['{0}'.format(i) for i in range(100, 100000, 100)]
%timeit q=[str(i) for i in range(100, 100000, 100)]
%timeit q=['{}'.format(i) for i in range(100, 100000, 100)]
1000 loops, best of 3: 231 µs per loop
1000 loops, best of 3: 298 µs per loop
1000 loops, best of 3: 434 µs per loop
来自 object.__str__(self)
docs
Called by str(object)
and the built-in functions format()
and print()
to compute the “informal” or nicely printable string representation of an object.
所以,str()
和 format()
调用相同的 object.__str__(self)
方法,但是速度上的差异从何而来?
更新
正如@StefanPochmann 和@Leon 在评论中指出的那样,他们得到了不同的结果。我尝试用 python -m timeit "..."
来 运行 它,他们是对的,因为结果是:
$ python3 -m timeit "['{0}'.format(i) for i in range(100, 100000, 100)]"
1000 loops, best of 3: 441 usec per loop
$ python3 -m timeit "[str(i) for i in range(100, 100000, 100)]"
1000 loops, best of 3: 297 usec per loop
$ python3 -m timeit "['{}'.format(i) for i in range(100, 100000, 100)]"
1000 loops, best of 3: 420 usec per loop
看来 IPython 正在做一些奇怪的事情...
新问题:将对象按速度转换为 str
的首选方法是什么?
IPython 计时由于某种原因刚刚关闭(尽管在不同的单元格中使用更长的格式字符串进行测试时,它的表现 稍微好一些 )。也许在同一个单元格中执行是不对的,真的不知道。
无论哪种方式,"{}"
比 "{pos}"
快一点,后者比 "{name}"
快一点,而它们都比 str
慢。
str(val)
是将对象转换为str
最快的方法;它直接调用对象的 __str__
(如果存在)和 returns 结果字符串。其他的,如 format
,(或 str.format
)包括额外的开销,因为额外的函数调用(对 format
本身);处理任何参数,解析格式字符串和 然后 调用它们的 args
.
的 __str__
对于str.format
方法"{}"
使用自动编号;来自 docs on the format syntax 中的一小部分:
Changed in version 3.1: The positional argument specifiers can be omitted, so '{} {}'
is equivalent to '{0} {1}'
.
也就是说,如果您提供以下形式的字符串:
"{}{}{}".format(1, 2, 3)
CPython 立即知道这相当于:
"{0}{1}{2}".format(1, 2, 3)
使用包含表示位置的数字的格式字符串; CPython 不能假定一个严格递增的数字(从 0
开始)并且必须解析每个括号以使其正确,这会减慢过程中的速度:
"{1}{2}{0}".format(1, 2, 3)
这就是为什么也不允许将这两者混合在一起的原因:
"{1}{}{2}".format(1, 2, 3)
如果您尝试这样做,您会得到很好的 ValueError
回报:
ValueError: cannot switch from automatic field numbering to manual field specification
它还抓取了这些 positionals with PySequence_GetItem
,我敢肯定它很快,至少与 PyObject_GetItem
相比[见下一个]。
对于 "{name}"
值,CPython 总是有额外的工作要做,因为我们处理的是关键字参数而不是位置参数;这包括诸如为调用构建字典和生成更多 LOAD
字节码指令以加载 key
和值之类的事情。函数调用的关键字形式总是会引入一些开销。此外,似乎抓取实际上使用了 PyObject_GetItem
,由于其通用性,它会产生一些额外的开销。
所以这是一个 CPython 的东西,不太确定它与其他实现有相同的行为。
但是 '{0}'.format()
比 str()
和 '{}'.format()
快。我正在发布 Python 3.5.2 的结果,但是,我尝试使用 Python 2.7.12 和趋势是一样的。
%timeit q=['{0}'.format(i) for i in range(100, 100000, 100)]
%timeit q=[str(i) for i in range(100, 100000, 100)]
%timeit q=['{}'.format(i) for i in range(100, 100000, 100)]
1000 loops, best of 3: 231 µs per loop
1000 loops, best of 3: 298 µs per loop
1000 loops, best of 3: 434 µs per loop
来自 object.__str__(self)
docs
Called by
str(object)
and the built-in functionsformat()
andprint()
to compute the “informal” or nicely printable string representation of an object.
所以,str()
和 format()
调用相同的 object.__str__(self)
方法,但是速度上的差异从何而来?
更新
正如@StefanPochmann 和@Leon 在评论中指出的那样,他们得到了不同的结果。我尝试用 python -m timeit "..."
来 运行 它,他们是对的,因为结果是:
$ python3 -m timeit "['{0}'.format(i) for i in range(100, 100000, 100)]"
1000 loops, best of 3: 441 usec per loop
$ python3 -m timeit "[str(i) for i in range(100, 100000, 100)]"
1000 loops, best of 3: 297 usec per loop
$ python3 -m timeit "['{}'.format(i) for i in range(100, 100000, 100)]"
1000 loops, best of 3: 420 usec per loop
看来 IPython 正在做一些奇怪的事情...
新问题:将对象按速度转换为 str
的首选方法是什么?
IPython 计时由于某种原因刚刚关闭(尽管在不同的单元格中使用更长的格式字符串进行测试时,它的表现 稍微好一些 )。也许在同一个单元格中执行是不对的,真的不知道。
无论哪种方式,"{}"
比 "{pos}"
快一点,后者比 "{name}"
快一点,而它们都比 str
慢。
str(val)
是将对象转换为str
最快的方法;它直接调用对象的 __str__
(如果存在)和 returns 结果字符串。其他的,如 format
,(或 str.format
)包括额外的开销,因为额外的函数调用(对 format
本身);处理任何参数,解析格式字符串和 然后 调用它们的 args
.
__str__
对于str.format
方法"{}"
使用自动编号;来自 docs on the format syntax 中的一小部分:
Changed in version 3.1: The positional argument specifiers can be omitted, so
'{} {}'
is equivalent to'{0} {1}'
.
也就是说,如果您提供以下形式的字符串:
"{}{}{}".format(1, 2, 3)
CPython 立即知道这相当于:
"{0}{1}{2}".format(1, 2, 3)
使用包含表示位置的数字的格式字符串; CPython 不能假定一个严格递增的数字(从 0
开始)并且必须解析每个括号以使其正确,这会减慢过程中的速度:
"{1}{2}{0}".format(1, 2, 3)
这就是为什么也不允许将这两者混合在一起的原因:
"{1}{}{2}".format(1, 2, 3)
如果您尝试这样做,您会得到很好的 ValueError
回报:
ValueError: cannot switch from automatic field numbering to manual field specification
它还抓取了这些 positionals with PySequence_GetItem
,我敢肯定它很快,至少与 PyObject_GetItem
相比[见下一个]。
对于 "{name}"
值,CPython 总是有额外的工作要做,因为我们处理的是关键字参数而不是位置参数;这包括诸如为调用构建字典和生成更多 LOAD
字节码指令以加载 key
和值之类的事情。函数调用的关键字形式总是会引入一些开销。此外,似乎抓取实际上使用了 PyObject_GetItem
,由于其通用性,它会产生一些额外的开销。