4

我有 collections.Counter 类的实例,也有一些对象,例如:

p1 = Person(name='John')
p2 = Person(name='John')
p3 = Person(name='Jane')

我想在 Counter 的实例中保存这个人对象的计数,考虑到具有相同名称的人对象必须增加相同的人数,所以如果我有一个包含所有人对象的列表:

people = [p1, p2, p3]

我用它填充我的计数器:

c = Counter(people)

我想得到以下信息:

c[p1] #prints 2
c[p2] #prints 2
c[p3] #prints 1

我的第一次尝试是为 person 对象实现一个新__eq__方法

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

我认为这可能会起作用,因为计数器对象似乎会根据键对象的相等性来增加键的计数,例如:

c = Counter(['A', 'A', 'B'])
c['A'] #prints 2
c['B'] #prints 1

另一种尝试可能是从 Counter 继承并覆盖 Counter 用于测量对象之间相等性的底层方法,我不确定,但我认为 Counter 使用__contains__方法。

我的问题是,是否有任何方法可以在不使用继承的情况下获得这种行为,如果没有,最好的方法是什么?

4

2 回答 2

8

您还必须实施__hash__

class Person(object):
    def __init__(self, name=None, address=None):
        self.name = name
        self.address = address

    def __eq__(self, other):
        return self.name == other.name and self.address == other.address

    def __hash__(self):
        return hash((self.name, self.address))

现在您的代码有效:

>>> Counter(people)
Counter({<__main__.Person object at 0x24a7590>: 2, <__main__.Person object at 0x24a75d0>: 1})
于 2013-02-02T22:53:22.747 回答
2

如果您的对象像您的示例中那样简单,请使用collections.namedtuple

from collections import Counter, namedtuple
Person = namedtuple('Person','name')

n1 = Person(name='John')
n2 = Person(name='John')
n3 = Person(name='Jane')
Counter((n1,n2,n3))
# Counter({Person(name='John'): 2, Person(name='Jane'): 1})
于 2013-02-02T22:58:47.863 回答