В настоящее время я работаю с некоторыми структурами данных в Python, и я хотел бы, чтобы они были хэшируемыми (чтобы их можно было хранить в словарях и наборах).До сих пор я видел три основных способа сделать это:
① Создать нормальный класс и дать ему __hash__
метод.
class DataStructure:
def __init__(self, member):
self.member = member
def __hash__(self):
return hash(self.member)
def __eq__(self, other):
return isinstance(other, DataStructure) and self.member == other.member
Но это просто "доверять"конечный пользователь никогда не мутирует member
.Если они изменяют его, пока он хранится в наборе или в словаре, получаются плохие вещи.
② Использовать collections.namedtuple
.
DataStructure = collections.namedtuple('DataStructure', ('member',))
Но namedtuple
не может иметь функции-членыи было бы неплохо иметь функции-члены.
③ Использовать __slots__
и переопределить __setattr__
, как показано здесь .
class DataStructure:
__slots__ = ['member']
def __init__(self, member):
super(DataStructure, self).__setattr__('member', member)
def __setattr__(self, key, value):
raise ValueError('Mutating this object is Not Allowed')
# also define __hash__ and __eq__ here
Но это не похоже на предполагаемое использование , а также усложняет наследование.Прежде всего, он не чувствует себя «Pythonic».
Итак: каков предпочтительный способ создания неизменяемого класса в Python? Желательно, чтобы пользовательская структура данных была хэшируемойкак такое странное желание - вот почему, в конце концов, существует __hash__
.И я бы предпочел сделать класс неизменным, а не говорить пользователям: «Вы можете назначать этих участников, но если вы это сделаете, ваши наборы и словари могут зависнуть и сгореть» - Python обычно старается не позволять людям делать это.ошибки в первую очередь (именно поэтому set
и frozenset
различны).