2016-11-25 4 views
2

Я определил класс, который я пытаюсь сделать hashable. Кроме того, существует перечисление, которое использует объекты этого класса в качестве значений его членов перечисления.Взаимодействие класса hashable с Enum в Python

from enum import Enum 


class Dummy(object): 
    def __init__(self, name, property_): 
     self.name = name    # can only be a string 
     self.property = property_ # can only be a string 

    def __hash__(self): 
     # print "Hash called for ", self 
     # print("----") 
     return hash(self.property) 

    def __eq__(self, other): 
     # print "Eq called for: " 
     # print self 
     # print other 
     return (self.property == other.property) 

    def __ne__ (self, other): 
     return not (self == other) 

    def __str__(self): 
     return (self.name + "$" + self.property) 


class Property(Enum): 
    cool = Dummy("foo", "cool") 
    hot = Dummy("bar", "hot") 

Хотя это работает отлично, я заметил, - ип-Комментирование print заявления - что __hash__ и __eq__ магические методы вызываются для двух перечисляемых значений членов. Почему это так? Разве они не используются только во время проверок хэширования и равенства?

Кроме того, если я изменю класс перечисления на следующий, все ад сломается.

class Property(Enum): 
    cool = Dummy("foo", "cool") 
    hot = [Dummy("bar-1", "hot-1"), Dummy("bar-2", "hot-2")] 

__eq__ магический метод, кажется, называется для Dummy объекта, соответствующего Property.cool и список, соответствующий Property.hot, как видно из вывода:

Hash called for foo$cool 
---- 
Eq called for: 
foo$cool 
[<__main__.Dummy object at 0x7fd36633f2d0>, <__main__.Dummy object at 0x7fd36633f310>] 
---- 
Traceback (most recent call last): 
    File "test.py", line 28, in <module> 
    class Property(Enum): 
    File "/blah/.local/lib/python2.7/site-packages/enum/__init__.py", line 237, in __new__ 
    if canonical_member.value == enum_member._value_: 
    File "test.py", line 19, in __eq__ 
    return (self.property is other.property) 
AttributeError: 'list' object has no attribute 'property' 

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

Обратите внимание, что это только типичный пример, и реальный прецедент делает этот проект - перечисление со значениями в виде списков объектов класса хэшируемых объектов - выглядит менее странным.

ответ

2

Класс Enum сравнивает значения объекта-члена, чтобы увидеть, являются ли какие-либо псевдонимы другого. Например, в следующем Enum, как a и b представляют одинаковое значение, так что только a должны отображаться в списке участников (псевдонимы нет):

class A(Enum): 
    a=1 
    b=1 

Вы можете убедиться в этом, посмотрев на источник код для линии, которая провела проверку равенства: source

Для хэширования это делается для обеспечения пошагового поиска элементов перечисления. Опять же, это можно найти в source code

+0

Это отвечает всем; Благодарю. Таким образом, значения элементов перечисления не могут быть изменчивым объектом, например списком, который не является хешируемым. – Shobhit

+1

Они могут быть. Если значение не хешируется, оно не будет включаться в таблицу поиска по значению, поэтому попытка найти его по значению будет проходить через члены и проверять равенство вместо – 3Doubloons