为什么在比较 python 对象元组时__eq__然后__cmp__调用



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

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__不被调用,而在第一种情况下,显然元组的第一个 elle 是通过相等然后通过 cmp 进行比较的。但是为什么不直接通过 cmp 比较它们?我真的不太明白的是缺少 cmp 或键参数的默认sorted行为。

元组比较就是这样实现的: 元组比较

它搜索项目不同的第一个索引,然后进行比较。这就是为什么您会看到一个__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)

相关内容

  • 没有找到相关文章

最新更新