Класс Custom __eq__ как Сравнение Хэшей - PullRequest
0 голосов
/ 01 марта 2019

Рассмотрим пользовательский класс:

class MyObject:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __hash__(self):
        return hash((self.a, self.b))

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return self.__hash__() == other.__hash__()

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

self.a == other.a and self.b == other.b and ... self.n == other.n

или более динамическая проверка с использованием getattr и списка (есть ли лучшийспособ сравнить большое количество пар атрибутов?)

Разве размер хеша, возвращаемого встроенной хеш-функцией, недостаточно велик, чтобы быть надежным в относительно больших наборах данных?

1 Ответ

0 голосов
/ 01 марта 2019

Да, это плохая идея.Хеши не являются уникальными, объекты с одинаковыми хэшами не гарантированно также будут фактически равны:

>>> (-1, 0) == (-2, 0)
False
>>> hash((-1, 0)) == hash((-2, 0))
True

Хэши не означают быть уникальными;они являются средством быстрого выбора слота в хэш-таблице ограниченного размера , чтобы упростить O (1) поиск в словаре, а коллизии разрешены и ожидаемы .

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

Я просто сравниваю кортежи:

def __eq__(self, other):
    return (self.a, self.b) == (other.a, other.b)

Если вынаписание большого количества классов данных , простых классов, которые требуют проверки на равенство и хэширования и т. д., используют модуль dataclasses (Python 3.7 или более поздней версии, или backport):

from dataclasses import dataclass

@dataclass(frozen=True)
class MyObject:
    a: int
    b: int

Вышеупомянутый класс теперь поставляется с __hash__ и __equals__ методом:

>>> MyObject(-1, 0) == MyObject(-2, 0)
False
>>> hash(MyObject(-1, 0)) == hash(MyObject(-2, 0))
True
>>> MyObject(42, 12345) == MyObject(42, 12345)
True
...