добавить объект в набор наборов python и определить по атрибуту объекта

У меня есть такой класс Person:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __repr__(self):
        return '<Person {}>'.format(self.name)

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

tom = Person('tom', 18)
mary = Person('mary', 22)
mary2 = Person('mary2', 22)

person_set = {tom, mary, mary2}
print(person_set)
# output: {<Person tom>, <Person mary>, <Person mary2>}

Как видите, в наборе 2 Марии. Как мне сделать так, чтобы Person экземпляра одного возраста считались одним и тем же человеком и добавлялись в набор только один раз?

Другими словами, как я могу получить результат {<Person tom>, <Person mary>}?


person sashimi    schedule 11.05.2012    source источник
comment
Итак, например, Frank, age 19 будет таким же, как Heather, age 19, если вы просто сравниваете по возрасту?   -  person jamylak    schedule 11.05.2012
comment
да, будет сохранен только первый добавленный в набор   -  person sashimi    schedule 11.05.2012
comment
@sashimi, тогда вам нужен словарь с возрастом в качестве ключа и объектом Person в качестве значения.   -  person spinlok    schedule 11.05.2012
comment
@spinlok, я думаю, ему просто нужно реализовать __hash__.   -  person jamylak    schedule 11.05.2012


Ответы (1)


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

В результате вам необходимо реализовать __hash__(...) и __eq__(...) в вашем классе. Например:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

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

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

    def __repr__(self):
        return '<Person {}>'.format(self.name)

tom = Person('tom', 18)
mary = Person('mary', 22)
mary2 = Person('mary2', 22)

person_set = {tom, mary, mary2}
print(person_set)
# output: {<Person tom>, <Person mary>}

Однако вам следует очень тщательно подумать о том, какой должна быть правильная реализация __hash__ и __eq__ для вашего класса. Приведенный выше пример работает, но не имеет смысла (например, в том, что и __hash__, и __eq__ определяются только с точки зрения возраста).

person srgerg    schedule 11.05.2012
comment
спасибо ~ это то, что я хочу, я знаю, что это странно. класс, такой как Person, который я буду использовать, очень прост. поэтому не имеет значения, перезаписывать или нет. я знаю, что это нежелательно ^_ ^, я буду использовать его осторожно - person sashimi; 11.05.2012
comment
Почему python даже требует указания метода __eq__, если он уже выполняет сравнение значения, указанного в __hash__? - person wesinat0r; 16.06.2020
comment
Я ответил на свой комментарий - docs.python.org/3/glossary.html# term-hashable __hash__ для значения времени существования объекта, __eq__ для сравнения с другими объектами. Вам все еще нужны оба, чтобы сделать сравнение - person wesinat0r; 16.06.2020
comment
hynek.me/articles/hashes-and-equality — хорошая статья, чтобы узнать больше фон - person wesinat0r; 17.06.2020