python str translate_Python str.translate与str.rep

本文探讨了Python 2.7中string模块的translate和replace方法的源代码,并通过cProfile进行性能测试。结果显示,在特定输入条件下,translate方法在C源代码层面的实现比replace更快。分析了dis模块输出的字节码,指出这是因为translate利用了针对特定情况的优化函数。结论是,对于某些操作,内置的C实现可能提供更好的性能。
摘要由CSDN通过智能技术生成

假设Python 2.7(因为我不得不在没有声明的情况下掷硬币),我们可以在string.py中找到string.translate和string.replace的源代码:>>> import inspect

>>> import string

>>> inspect.getsourcefile(string.translate)

'/usr/local/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/lib/python2.7/string.py'

>>> inspect.getsourcefile(string.replace)

'/usr/local/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/lib/python2.7/string.py'

>>>

哦,我们不能,as string.py开始于:"""A collection of string operations (most are no longer used).

Warning: most of the code you see here isn't normally used nowadays.

Beginning with Python 1.6, many of these functions are implemented as

methods on the standard string object.

我投了你一票,因为你是从分析开始的,所以让我们继续往下讲:from cProfile import run

from string import ascii_letters

s = '1 a 2'

def _replace():

for x in range(5000000):

s.replace(' ', '')

def _translate():

for x in range(5000000):

s.translate(None, ' ')

替换:run("_replace()")

5000004 function calls in 2.059 seconds

Ordered by: standard name

ncalls tottime percall cumtime percall filename:lineno(function)

1 0.976 0.976 2.059 2.059 :8(_replace)

1 0.000 0.000 2.059 2.059 :1()

1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}

5000000 1.033 0.000 1.033 0.000 {method 'replace' of 'str' objects}

1 0.050 0.050 0.050 0.050 {range}

对于翻译:run("_translate()")

5000004 function calls in 1.785 seconds

Ordered by: standard name

ncalls tottime percall cumtime percall filename:lineno(function)

1 0.977 0.977 1.785 1.785 :12(_translate)

1 0.000 0.000 1.785 1.785 :1()

1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}

5000000 0.756 0.000 0.756 0.000 {method 'translate' of 'str' objects}

1 0.052 0.052 0.052 0.052 {range}

我们的函数调用数量是相同的,并不是说更多的函数调用意味着运行速度会变慢,但它通常是一个很好的地方。有趣的是,translate在我的机器上比replace跑得快!考虑一下不单独测试变化的乐趣——这并不重要,因为我们只关心为什么可以有区别。

无论如何,我们至少现在知道可能存在性能差异,并且在评估字符串对象的方法时确实存在这种差异(请参见tottime)。translate__docstring__表示有一个翻译表在运行,而replace只提到从旧到新的子字符串替换。

让我们向我们的老朋友^{}寻求提示:from dis import dis

替换:def dis_replace():

'1 a 2'.replace(' ', '')

dis(dis_replace)

dis("'1 a 2'.replace(' ', '')")

3 0 LOAD_CONST 1 ('1 a 2')

3 LOAD_ATTR 0 (replace)

6 LOAD_CONST 2 (' ')

9 LOAD_CONST 3 ('')

12 CALL_FUNCTION 2

15 POP_TOP

16 LOAD_CONST 0 (None)

19 RETURN_VALUE

还有translate,对我来说跑得更快:def dis_translate():

'1 a 2'.translate(None, ' ')

dis(dis_translate)

2 0 LOAD_CONST 1 ('1 a 2')

3 LOAD_ATTR 0 (translate)

6 LOAD_CONST 0 (None)

9 LOAD_CONST 2 (' ')

12 CALL_FUNCTION 2

15 POP_TOP

16 LOAD_CONST 0 (None)

19 RETURN_VALUE

不幸的是,这两个看起来与dis完全相同,这意味着我们应该从这里开始查找字符串的C源代码(通过转到我现在使用的python版本的python源代码可以找到)](https://hg.python.org/cpython/file/a887ce8611d2/Objects/stringobject.c)。

这是source for translate。

如果您查看注释,可以看到基于输入的长度有多个replace函数定义行。

我们的子串替换选项是:/* len(self)>=1, len(from)==len(to)>=2, maxcount>=1 */

Py_LOCAL(PyStringObject *)

replace_substring_in_place(PyStringObject *self,/* len(self)>=1, len(from)>=2, len(to)>=2, maxcount>=1 */

Py_LOCAL(PyStringObject *)

replace_substring(PyStringObject *self,/* Special case for deleting a single character */

/* len(self)>=1, len(from)==1, to="", maxcount>=1 */

Py_LOCAL(PyStringObject *)

replace_delete_single_character(PyStringObject *self,

char from_c, Py_ssize_t maxcount)

'1 a 2'.replace(' ', '')是len(self)==6,用空字符串替换1个字符,使其成为replace_delete_single_character。

您可以自己检查函数体,但答案是“对于这个特定输入,C函数体在replace_delete_single_character中的运行速度比string_translate快。

谢谢你问这个问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值