Равенство объектов в коллекциях Python. Счетчик

У меня есть и экземпляр коллекций. Класс класса, также у меня есть несколько объектов, таких как:

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

Я хочу сохранить количество объектов этого человека в экземпляре счетчика, принимая во внимание, что объекты человека с одинаковыми именами должны увеличивать одно и то же число людей, поэтому, если у меня есть список со всеми объектами человека:

people = [p1, p2, p3]

и я заполнил свой счетчик этим:

c = Counter(people)

я хочу получить следующее:

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

Моей первой попыткой было реализовать новый __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__ метод для этого.

Мой вопрос: есть ли способ получить такое поведение без использования наследования, и если нет, то какой может быть лучший способ сделать это?

2 ответа

Решение

Вы также должны реализовать __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})

Если ваши объекты просты, как в вашем примере, используйте 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})
Другие вопросы по тегам