比较startswith().vs的速度。在()

时间:2017-06-13 11:25:24

标签: python performance python-3.x time

我的印象是startswith 必须比in更快,原因很简单in必须做更多检查(允许被查找的单词在字符串中的任何位置。但我有疑虑所以我决定timeit。时间的代码如下所示,你可能会注意到我没有做太多时间;代码很简单。

import timeit

setup1='''
def in_test(sent, word):
    if word in sent:
        return True
    else:
        return False
'''

setup2='''
def startswith_test(sent, word):
    if sent.startswith(word):
        return True
    else:
        return False
'''

print(timeit.timeit('in_test("this is a standard sentence", "this")', setup=setup1))
print(timeit.timeit('startswith_test("this is a standard sentence", "this")', setup=setup2))

结果:

>> in:         0.11912814951705597
>> startswith: 0.22812353561129417

所以startswith慢了两倍!我发现这个行为非常令人费解,因为我上面已经说过了。我对两个计时器做错了还是in确实更快?如果是这样,为什么?

请注意,即使它们都返回False,结果也非常相似(在这种情况下,in必须实际遍历整个句子,以防它只是短路之前):

print(timeit.timeit('in_test("another standard sentence, would be that", "this")', setup=setup1))
print(timeit.timeit('startswith_test("another standard sentence, would be that", "this")', setup=setup2))

>> in:         0.12854891578786237
>> startswith: 0.2233201940338861

如果必须从头开始实现这两个函数,它看起来像这样(伪代码):

startswith :开始逐一将 word 的字母与句子的字母进行比较,直到a)字耗尽为止(返回True)或b)检查返回False(返回False)

in :在句子中找到 word 首字母的每个位置,请致电startswith

我只是不明白..

为了说清楚,instartswith 不等同;我只是在谈论一个人试图找到的单词必须是字符串中 first 的情况。

3 个答案:

答案 0 :(得分:8)

这是因为您必须查找并调用方法。 in是专门的,直接指向COMPARE_OP(调用cmp_outcome,后者调用PySequence_Contains)而str.startswith通过较慢的字节代码:

2 LOAD_ATTR                0 (startswith)
4 LOAD_FAST                1 (word)
6 CALL_FUNCTION            1              # the slow part

in替换__contains__,强制对该案例进行函数调用,几乎否定了速度差异:

setup1='''
def in_test(sent, word):
    if sent.__contains__(word):
        return True
    else:
        return False
'''

而且,时间安排:

print(timeit.timeit('in_test("this is a standard sentence", "this")', setup=setup1))
print(timeit.timeit('startswith_test("this is a standard sentence", "this")', setup=setup2))
0.43849368393421173
0.4993997460696846

in在这里获胜是因为它不需要经历整个函数调用设置,并且由于它提供的有利情况。

答案 1 :(得分:5)

您在字符串-vs-属性查找和函数调用上比较运算符。第二个将有更高的开销,即使第一个需要很长时间的大量数据。

此外,您正在查找第一个字,因此如果匹配,in将查看与startswith()一样多的数据。要看到差异,你应该看一个悲观的情况(没有找到结果,或者在字符串的末尾匹配):

setup1='''
data = "xxxx"*1000
def ....

print(timeit.timeit('in_test(data, "this")', setup=setup1))
0.932795189000899
print(timeit.timeit('startswith_test(data, "this")', setup=setup2))
0.22242475600069156

答案 2 :(得分:0)

如果查看函数产生的字节码:

>>> dis.dis(in_test)
  2           0 LOAD_FAST                1 (word)
              3 LOAD_FAST                0 (sent)
              6 COMPARE_OP               6 (in)
              9 POP_JUMP_IF_FALSE       16

  3          12 LOAD_CONST               1 (True)
             15 RETURN_VALUE

  5     >>   16 LOAD_CONST               2 (False)
             19 RETURN_VALUE
             20 LOAD_CONST               0 (None)
             23 RETURN_VALUE

你会注意到有很多与字符串匹配没有直接关系的开销。在更简单的函数上进行测试:

def in_test(sent, word):
    return word in sent

会更可靠。