2

根据Python 参考手册

字符串使用其字符的数字等价物(内置函数 ord() 的结果)按字典顺序进行比较。Unicode 和 8 位字符串在此行为中是完全可互操作的。

意思是散列不用于此目的。

现在,假设在相等性测试期间,Python 在内部首先检查两个字符串的长度并继续进行字典比较,如果两者的长度相同(我想它对所有其他比较也一样)。

好吧,如果是这样,那么为什么以下两个不同的比较会消耗不同的时间?

>>> str1 = "foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge1"
>>> 
>>> str2 = "foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge2"
>>> 
>>> def compare():
     t1 = time.time()
     for x in xrange(100000000):
         str1 == str2
     print time.time() - t1
 
>>> 
>>> compare()
13.001019001
>>> 
>>> str2 = "foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge1"
>>> 
>>> compare()
7.41645097733

在这两个比较中str1str2是相同的长度。在第一个中,两者仅在最后一个字符上有所不同,而在第二个中则没有。

PS:使用长字符串和大迭代来使差异明显。

4

4 回答 4

1

在 Python 中有一些字符串字面量,就像在许多语言中一样,在第二种情况下,两个字符串实际上是同一个对象,因此它们是通过引用而不是实际值进行比较的。

基于引用的语言中典型的字符串比较函数:

if (ref(a) == ref(b)) return true;
if (len(a) != len(b)) return false;
return compare_actual_data(a, b);
于 2012-09-16T14:42:22.617 回答
1

正如其他答案所推测的那样,如果字符串相同,则比较确实是短路的,具有相同内容的字符串文字就是这种情况。

于 2012-09-16T14:47:31.043 回答
1

在第二种情况下,这两个字符串实际上是同一个对象,具有相同的 id。

str1 = "foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge1"
str2 = "foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge2"

def compare():
    t1 = time.time()
    for x in xrange(100000000):
        str1 == str2
    print time.time() - t1


print "%d, %d" % (id(str1), id(str2))
compare()

str2 = "foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge_foo_bar_cruft_kludge1"

print "%d, %d" % (id(str1), id(str2))
compare()

在第二种情况下,id 是相同的,因此 python 解释器不必逐字节比较整个字符串。

于 2012-09-16T14:49:49.563 回答
0

如果两个字符串是'interned',那么它们可以通过指针比较进行比较。也许在这种情况下,字节码生成器注意到字符串是常量并将它们实习?

您可以通过证明较小的时间在很大程度上独立于(或不)于字符串的长度来证明(或反驳)这一点。

事实上,我得到了这些结果:

$ ./test.py 
17.4877259731
8.61179995537
$ ./test_halflengthstrings.py 
12.6504788399
8.58732700348
于 2012-09-16T14:41:14.317 回答