首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么str.strip()比str.strip(‘)快得多?

为什么str.strip()比str.strip(‘)快得多?
EN

Stack Overflow用户
提问于 2016-07-09 19:38:30
回答 2查看 4.3K关注 0票数 32

使用str.strip可以通过两种方式在空白上进行拆分。您可以发出没有参数的调用,str.strip() (默认使用空白分隔符),也可以使用str.strip(' ')显式地自己提供参数。

但是,为什么这些函数在计时时表现得如此不同呢?

使用带有有意空白的示例字符串:

代码语言:javascript
复制
s = " " * 100 + 'a' + " " * 100

s.strip()s.strip(' ')的时间分别为:

代码语言:javascript
复制
%timeit s.strip()
The slowest run took 32.74 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 396 ns per loop

%timeit s.strip(' ')
100000 loops, best of 3: 4.5 µs per loop

strip采用396ns,而strip(' ')采用4.5 μs,在相同的条件下,rstriplstrip也会出现类似的场景。还有, seem do be affected too

时间是为Python 3.5.2执行的,而在Python 2.7.1上则没有太大的差别。str.strip没有指出任何有用的东西,所以,为什么会发生这种情况?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-07-09 19:38:30

以一种流行的方式:

这是因为对于这两种不同的情况,存在两个函数,在unicode_strip中可以看到;do_strip_PyUnicodeXStrip --第一个函数的执行速度比第二个函数快得多。

函数do_strip用于不存在参数的公共情况str.strip()和调用str.strip(arg)的情况下的do_argstrip (包装_PyUnicode_XStrip),即提供参数。

do_argstrip只检查分隔符,如果它有效且不等于None (在这种情况下它调用do_strip),则调用_PyUnicode_XStrip

do_strip_PyUnicode_XStrip都遵循相同的逻辑,使用两个计数器,一个等于零,另一个等于字符串的长度。

使用两个while循环,第一个计数器被递增,直到达到一个不等于分隔符的值,第二个计数器被递减,直到满足相同的条件。

区别在于检查当前字符是否等于分隔符的方式。

对于do_strip

在最常见的情况下,要拆分的字符串中的字符可以用ascii表示,这会带来额外的小性能提升。

代码语言:javascript
复制
while (i < len) {
    Py_UCS1 ch = data[i];
    if (!_Py_ascii_whitespace[ch])
        break;
    i++;
}
  • 通过访问基础数组:Py_UCS1 ch = data[i];,可以快速访问数据中的当前字符
  • 检查某个字符是否为空白,由一个简单的数组索引对一个名为_Py_ascii_whitespace[ch]的数组进行检查。

因此,简而言之,它是相当有效的。

如果字符不在ascii范围内,差异并不那么大,但它们确实减缓了整个执行过程:

代码语言:javascript
复制
while (i < len) {
    Py_UCS4 ch = PyUnicode_READ(kind, data, i);
    if (!Py_UNICODE_ISSPACE(ch))
        break;
    i++;
}
  • 访问是用Py_UCS4 ch = PyUnicode_READ(kind, data, i);完成的
  • 检查字符是否为空格是由Py_UNICODE_ISSPACE(ch)宏完成的(只需调用另一个宏:Py_ISSPACE)

对于_PyUnicodeXStrip

在这种情况下,访问底层数据,就像在前面的例子中一样,是用PyUnicode_Read完成的;另一方面,检查该字符是否是空白(或者实际上是我们提供的任何字符)要稍微复杂一些。

代码语言:javascript
复制
while (i < len) {
     Py_UCS4 ch = PyUnicode_READ(kind, data, i);
     if (!BLOOM(sepmask, ch))
         break;
     if (PyUnicode_FindChar(sepobj, ch, 0, seplen, 1) < 0)
         break;
     i++;
}

使用PyUnicode_FindChar,虽然效率很高,但比数组访问要复杂得多,速度也慢得多。对于字符串中的每个字符,将调用该字符以查看该字符是否包含在我们提供的分隔符中。随着字符串长度的增加,调用此函数所带来的开销也会增加。

对于那些感兴趣的人,PyUnicode_FindChar经过相当多的检查后,最终会在stringlib中调用find_char,在分隔符长度为< 10的情况下,将循环到找到字符为止。

除此之外,还需要考虑需要调用的附加函数才能到达这里。

至于lstriprstrip,情况也很相似。存在要执行的条带模式的标志,即:RIGHTSTRIP用于rstripLEFTSTRIP用于lstripBOTHSTRIP用于stripdo_strip_PyUnicode_XStrip内部的逻辑是根据标志有条件地执行的。

票数 34
EN

Stack Overflow用户

发布于 2016-07-09 21:24:51

由于@Jims中解释的原因,在bytes对象中也可以找到相同的行为:

代码语言:javascript
复制
b = bytes(" " * 100 + "a" + " " * 100, encoding='ascii')

b.strip()      # takes 427ns
b.strip(b' ')  # takes 1.2μs

对于bytearray对象,这种情况不会发生,在这种情况下,执行split的函数在这两种情况下都是相似的。

此外,根据我的时间表,在Python 2中,同样的情况在较小的程度上也适用。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38285654

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档