Когда два словарных ключа считаются равными для пользовательских типов? - PullRequest
0 голосов
/ 10 июня 2018

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

class DTest:
    def __init__(self,name):
        self.name = name
    def __eq__(self,other):
        return self.name == other.name
    def __hash__(self):
        return hash(self.name)
ob = DTest('kkk')
ob1 = DTest('kkk')
dict = {ob:1,ob1:2}

PS: я разработчик C ++, который начал работать на Python

Ответы [ 2 ]

0 голосов
/ 10 июня 2018

В ответ на ваши вопросы в комментариях, вот пример, показывающий, почему изменяемые типы обычно плохая идея для словарных ключей:

class MutableIntKey:
    def __init__(self, val):
        self.val = val

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

    def __hash__(self):
        return self.val

k = MutableIntKey(5)

d = {k: "Five"}
print(d)        # {<__main__.MutableIntKey object at 0x00000249DFBFA400>: 'Five'}
print(k in d)   # True

Пока все работает, но что еслиключ видоизменен ...

# Mutate k
k.val = 600

print(d)        # {<__main__.MutableIntKey object at 0x00000249DFBFA400>: 'Five'}
print(k in d)   # False

Теперь словарь не «думает», что ключ присутствует в словаре.

Но на самом деле ключ - это там ...

print(k in list(d.keys()))  # True

Теперь сделать пользовательский объект неизменяемым - не самая простая вещь в мире, но на самом деле вас волнует, что ключ dict неизменен.В частности, вы хотите убедиться, что свойства вашего ключа DICT, которые используются в __hash__ и __eq__, являются неизменяемыми или каким-либо иным образом защищены от изменений.

Самый простой, но наименее гибкий подход заключается в использованииссылаться на равенство в качестве теста __eq__ (по умолчанию) и использовать id(self) для реализации __hash__.Это гарантирует, что даже в случае мутации ключ будет найден.Недостатком является то, что единственный способ поиска ключа в словаре - это если у вас уже есть ссылка на этот точный объект.

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

Другой способ - создать неизменный объект, используя соответствующее пользовательское состояние объекта, и использовать его в качестве ключа.Небольшая трата памяти, но простая и выполняющая работу.

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

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

0 голосов
/ 10 июня 2018
class DTest:
    def __init__(self,name):
        self.name = name
    def __eq__(self,other):
        return self.name == other.name
    def __hash__(self):
        return hash(self.name)
ob = DTest('kkk')
ob1 = DTest('kkk')
d = {ob:1,ob1:2}

Если вы проверите количество элементов в словаре, оно будет только 1.

len(d)

дает результат как 1.

Python молча перезаписывает предыдущую запись.Обратите внимание, это отличается от C ++, где ваш второй ключ не будет вставлен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...