了解集合的python对象成员资格

时间:2010-09-09 18:30:04

标签: python collections membership set cmp

如果我理解正确,则会调用对象的__cmp __()函数,以便在确定对象是否为集合的成员或“in”时评估集合中的所有对象。 但是,对于集合来说似乎并非如此:

class MyObject(object):
    def __init__(self, data):
        self.data = data

    def __cmp__(self, other):
        return self.data-other.data

a = MyObject(5)
b = MyObject(5)

print a in [b]          //evaluates to True, as I'd expect
print a in set([b])     //evaluates to False

如何在集合中测试对象成员资格呢?

4 个答案:

答案 0 :(得分:5)

向您的班级添加__hash__方法会产生以下结果:

class MyObject(object):
    def __init__(self, data):
        self.data = data

    def __cmp__(self, other):
        return self.data - other.data

    def __hash__(self):
        return hash(self.data)


a = MyObject(5)
b = MyObject(5)

print a in [b] # True
print a in set([b]) # Also True!

答案 1 :(得分:2)

>>> xs = []
>>> set([xs])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

你有。设置使用哈希,非常类似于词典。这极其有助于性能(成员资格测试是O(1),许多其他操作依赖于成员资格测试),它也很好地符合集合的语义:设置项目必须是唯一的,不同的项目将产生不同的哈希值,而相同的哈希值表明(理论上)重复。

由于默认__hash__只是id(这是相当愚蠢的imho),继承object的{​​{1}}的类的两个实例永远不会哈希到相同的值(除非地址空间大于散列的__hash__)。

答案 2 :(得分:1)

正如其他人指出的那样,你的对象没有__hash__所以他们使用默认id作为哈希,你可以像Nathon建议的那样覆盖它,但是读{{3 ,特别是关于何时应该而且不应该这样做的要点。

答案 3 :(得分:0)

一个集合在幕后使用dict,因此“in”语句检查对象是否作为dict中的键存在。由于您的对象未实现散列函数,因此对象的默认散列函数使用对象的id。所以即使a和b是等价的,它们也不是同一个对象,而这正是被测试的。