Наборы экземпляров - PullRequest
       6

Наборы экземпляров

1 голос
/ 10 января 2010

Я пытаюсь создать набор экземпляров объекта, однако добавление экземпляров определенных объектов приводит к TypeError: unhashable instance. Вот минимальный пример:

from sets import Set
import random
from UserDict import DictMixin

class Item1(object):
    pass

class Item2(DictMixin):
    pass

item_collection = Set()

x = Item1()
y = Item2()

item_collection.add(x) # this works
print item_collection
item_collection.add(y) # this does not
print item_collection

Почему это терпит неудачу и как я могу получить набор экземпляров объекта, производного от DictMixin?

Ответы [ 2 ]

5 голосов
/ 10 января 2010

Чтобы положить вещи в набор, они должны быть хэшируемыми. Например, кортежи могут быть хэшируемыми, а списки - нет. Вы можете сделать свой объект хешируемым, дав ему метод __hash__, который сгенерирует для него хеш-ключ (уникальный идентификатор для этого экземпляра класса, зависящий от данных, которые он содержит).

Вот пример попытки добавить список в набор.

>>> x = [1,2,3]
>>> a=set()
>>> a.add(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

Похоже, ваш DictMixin класс не является хэшируемым.

4 голосов
/ 10 января 2010

Ваши классы могут, если хотите, определять __hash__ и методы сравнения (наиболее важно __eq__), чтобы они были согласованы друг с другом и были "стабильными" - т. Е. Равенство двух объектов не должно изменяться по объектам «время жизни и, конечно же, ни одно из значений хеш-функции каждого объекта не должно меняться в течение срока службы объекта.

Требование согласованности: a==b must подразумевает hash(a)==hash(b) (обратное не требуется, и действительно редко).

Так что, если вы согласны с этими требованиями, простейшей реализацией будет:

class Item2(DictMixin):
    def __hash__(self): return hash(id(self))
    def __eq__(self, x): return x is self
    def __ne__(self, x): return x is not self

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

x is self является более быстрым, более прямым и более кратким выражением id(x) == id(self), потому что , что - это значение оператора is - тождество id (т.е. объект).

Так значит ли это, что a==b заставляет означать то же самое, что и a is b, проблему для вашего приложения? Если это так, то наборы просто невозможно использовать для указанного приложения, и вам нужно подумать о какой-то другой, совершенно другой структуре данных (та, которая не основана на хешировании, потому что без переопределения __eq__ вы не сможете заставить хеширование работать правильно).

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