我的印象是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
我只是不明白..
为了说清楚,in
和startswith
不等同;我只是在谈论一个人试图找到的单词必须是字符串中 first 的情况。
答案 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
会更可靠。