如何从容器中删除相等的对象(但不一定是同一个对象)?

时间:2015-03-24 04:11:37

标签: python object set containers

我想做类似的事情:

class Thing(object):
    self.mySet = Set()
    self.mySet.add(Cell((0,0),25))
    self.mySet.add(Cell((0,1),50))
    self.mySet.add(Cell((0,2),75))

    def ClaimCell(self, cell):
        self.mySet.remove(cell)

class Cell(object):
    def __init__(self,index,value):
        self.index = index
        self.value = value

但实质上,我希望能够基于Cell的成员而不是实例本身进行查找。我希望能够测试传入的cell.index是否与cell.index中的self.mySet匹配。我可以为此覆盖__cmp__类型的方法吗?或者我被迫循环遍历Set,每次检查索引,然后手动删除相应的条目?

1 个答案:

答案 0 :(得分:1)

在Python中,两个相似的对象并不相同。引用__hash__

的文档
  

如果某个类未定义__cmp__()__eq__()方法,则不应定义__hash__()操作;如果它定义__cmp__()__eq__()但不定义__hash__(),则其实例将无法在散列集合中使用。如果一个类定义了可变对象并实现了__cmp__()__eq__()方法,那么它不应该实现__hash__(),因为hashable collection实现要求对象的哈希值是不可变的(如果对象的哈希值)更改,它将在错误的哈希桶中。)

     

默认情况下,用户定义的类具有__cmp__()__hash__()方法;与他们一起,所有对象比较不等(除了他们自己)和x.__hash__()返回从id(x)派生的结果。

因此,如果您想要将两个对象视为相同,则需要覆盖__eq____hash__方法,例如

class Cell(object):

    def __init__(self, index, value):
        self.index = index
        self.value = value

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

    def __eq__(self, other):
        return other.index == self.index

    def __repr__(self):
        return "Index: {}, Value: {}".format(self.index, self.value)

由于您要根据index进行比较,因此只会对index进行哈希处理,并在覆盖的__hash__方法中返回。

如果两个哈希值相等,那么Python将通过内部调用__eq__方法检查两个对象是否相同。因此,我们也覆盖了该方法,只返回比较两个对象index的结果

    def __eq__(self, other):
        return other.index == self.index

我们已经覆盖了__repr__,只是为了在打印时看到实际的元素。

现在,当你做这样的事情时

class Thing(object):

    def __init__(self):
        self.mySet = set()
        self.mySet.add(Cell((0, 0), 25))
        self.mySet.add(Cell((0, 1), 50))
        self.mySet.add(Cell((0, 2), 75))

    def ClaimCell(self, cell):
        self.mySet.remove(cell)
        print(self.mySet)

Thing().ClaimCell(Cell((0, 1), 99))

你会得到

set([Index: (0, 0), Value: 25, Index: (0, 2), Value: 75])

请注意,我们尝试删除的Cell对象的值为99,因为我们只考虑index进行对象识别,因此删除了Cell index (0, 1)