为什么比较对象的python元组是__eq__然后调用__cmp__?

时间:2016-05-29 18:53:46

标签: python python-2.7 sorting compare tuples

当比较对象的元组时,显然调用了对象的__eq__方法,然后是compare方法:

import timeit

setup = """
import random
import string
import operator

random.seed('slartibartfast')
d={}

class A(object):
    eq_calls = 0
    cmp_calls = 0
    def __init__(self):
        self.s = ''.join(random.choice(string.ascii_uppercase) for _ in
              range(16))
    def __hash__(self): return hash(self.s)
    def __eq__(self, other):
        self.__class__.eq_calls += 1
        return self.s == other.s
    def __ne__(self, other): return self.s != other.s
    def __cmp__(self, other):
        self.__class__.cmp_calls += 1
        return cmp(self.s ,other.s)

for i in range(1000): d[A()] = 0"""
print min(timeit.Timer("""
for k,v in sorted(d.iteritems()): pass
print A.eq_calls
print A.cmp_calls""", setup=setup).repeat(1, 1))

print min(timeit.Timer("""
for k,v in sorted(d.iteritems(),key=operator.itemgetter(0)): pass
print A.eq_calls
print A.cmp_calls""", setup=setup).repeat(1, 1))

打印:

8605
8605
0.0172435735131
0
8605
0.0103719966418

所以在我们比较键(即A实例)的第二种情况下,直接__eq__没有被调用,而在第一种情况下,显然元组的第一个元素通过相等然后通过cmp进行比较。但为什么不直接通过cmp进行比较呢?我真的不太明白的是缺少cmp或key参数时的默认sorted行为。

1 个答案:

答案 0 :(得分:2)

这是如何实现元组比较的:tuplerichcompare

它搜索项目不同的第一个索引,然后进行比较。这就是您看到__eq__然后__cmp__来电的原因。 此外,如果您没有为A实现__eq__运算符,您会看到__cmp__被调用两次以获得相等性,一次被用于比较。

例如,

print min(timeit.Timer("""
l =list()
for i in range(5): 
    l.append((A(),A(),A()))
    l[-1][0].s='foo'
    l[-1][1].s='foo2'
for _ in sorted(l): pass 
print A.eq_calls
print A.cmp_calls""", setup=setup).repeat(1, 1))

分别打印出24个和8个调用(具体数字明显取决于随机种子,但在这种情况下,它们的比率总是为3)