Автор: CoolPython
Пусть у нас есть сервер и его клиенты. На сервере мы хотим учитывать состояние клиентов и управлять ими. Для этого будем добавлять клиенты в множество, чтобы случайно не учесть один и тот же клиент на сервере дважды.
Создадим класс Client и добавим его в множество (сразу определила метод repr, чтобы были красивые принты):
class Client:
def __init__(self, user_name):
self.user_name = user_name
def __repr__(self):
return self.user_name
fish1 = Client(user_name="catfish")
clients = set()
clients.add(fish1)
print(clients) # {catfish} Круто, все работает из коробки! Попробуем теперь добавить второй клиент, чтобы увидеть, что дублирования нет:
fish2 = Client(user_name="catfish")
clients.add(fish2)
print(clients) # {catfish, catfish} Как же так? Мы добавили в множество два совершенно одинаковых экземпляра и ждали, что останется только один, но сохранились оба.
Интерпретатор при добавлении объекта в множество следует правилу:
если a == b, то обязательно hash(a) == hash(b)
То есть, сравнивает между собой как сами объекты, так и их хеши.
Для того, чтобы сравнивать объекты, множества и словари используют магический метод eq. Для пользовательских объектов он определен по умолчанию. И по умолчанию два разных объекта не равны, даже если они абсолютно идентичны:
print(fish1 == fish2) # False
По умолчанию все объекты в Python также хешируемы. Когда мы пытаемся добавить объект в множество, мы используем магический метод этого объекта hash, который тоже определен по умолчанию. Часто люди думают, что хеш объекта совпадает с его адресом в памяти, но это не всегда так:
hash(x) = id()hash(x)==id(x)/16 То есть, рассчитывать на то, что hash(x) = id(), нельзя. Но можно рассчитывать на то, что в Python-объектах по умолчанию есть hash, который зависит от id() и на то, что хеш объекта в течение его жизни не меняется.
Так как в нашем примере объекты разные и располагаются в разных ячейках памяти, то
print(hash(fish1), hash(fish2)) # 8786876890805 8786876904409
Так что делать, чтобы объекты, которые мы хотим считать одинаковыми, схлопывались во множестве? Перегрузить методы hash и eq, чтобы в явном виде дать интерпретатору инструкцию, как сравнивать объекты и как рассчитывать хеш.
Для этого исправим определение класса:
class Client:
def __init__(self, user_name):
self.user_name = user_name
def __repr__(self):
return self.user_name
def __hash__(self):
return hash(self.user_name)
def __eq__(self, other):
if self.user_name == other.user_name:
return True
else:
return False Теперь при добавлении объектов в множество все работает как ожидали:
clients = set()
fish1 = Client(user_name="catfish")
clients.add(fish1)
fish2 = Client(user_name="catfish")
clients.add(fish2)
print(clients) # {catfish} Помните, для того, чтобы объект класса, который вы определили сами, можно было добавить во множество или словарь, нужно:
hash и eq, причем оба, иначе не заработает.Если вы ищете работу на Python, на Talanto.work сейчас есть варианты для junior, middle, senior…
Рынок Python-вакансий большой, но удобным его назвать сложно. Формально вакансий много, однако в реальном поиске…
Срезы в Python — это больше, чем a[2:7]. В статье — быстрый разбор полезных приёмов:…
В этой статье мы рассмотрим возведение в степень в Python с помощью различных методов, от…
Дубликаты в списке Python — частая проблема. В статье показано, как быстро убрать повторы, в…
Услуга виртуального хостинга на SpaceWeb позволяет арендовать часть сервера (shared-сервера) и разместить на нём свой…