当比较对象的元组时,显然调用了对象的__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
行为。
答案 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)