python中两种子串搜索方法的效率比较

Comparing efficiency of two substring searching methods in Python

在搜索了python(link1,link2)中的子字符串搜索主题之后,我发现了两个明显的解决方案

1
2
3
4
5
6
7
8
str1 = 'Hi there'
str2 = 'Good bye'
# 1
if str1.find('Hi') != -1:
    print 'Success!'
# 2
if 'Good' in str2:
    print 'Success'
  • 这两个或第二个代码在生成的代码中有区别吗?仅仅是语法上的糖分?
  • 其中一个效率更高吗?
  • 有第三种选择吗


您可以检查这些条件下字节码的外观:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
In [1]: import dis

In [2]: dis.dis(lambda: 'Hi' in x)
  1           0 LOAD_CONST               1 ('Hi')
              3 LOAD_GLOBAL              0 (x)
              6 COMPARE_OP               6 (in)
              9 RETURN_VALUE        

In [3]: dis.dis(lambda: x.find('Hi') != -1)
  1           0 LOAD_GLOBAL              0 (x)
              3 LOAD_ATTR                1 (find)
              6 LOAD_CONST               1 ('Hi')
              9 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             12 LOAD_CONST               3 (-1)
             15 COMPARE_OP               3 (!=)
             18 RETURN_VALUE

正如您所看到的,find版本的功能要多得多,特别是它执行的是属性查找,而in操作符不需要这样做。

我还必须说,in使它更加明确,您正在检查子字符串的存在,而不是它的位置,因此它更可读。

在速度方面,它们对于任何合理尺寸的弦都应该是完全相等的。仅对于最小的字符串,属性查找具有显著的影响,但在这种情况下,条件检查速度非常快。

第三种选择是使用index并捕获例外:

1
2
3
4
5
6
try:
    string.index(substring)
except IndexError:
    # not found
else:
    # found

尽管不能用简单的表达式来表达。


第二个不只是第一个的句法糖分。str.find只是一个方法调用,而a in b调用a.__contains__(b)。我觉得速度没有什么差别。

我推荐第二种,因为它更像是Python:

它更可读。它使用鸭式打字。字符串可以被另一个iterable替换,它仍然可以工作。