Python中哈希类与枚举的交互

Python中哈希类与枚举的交互,python,python-2.7,hash,enums,magic-methods,Python,Python 2.7,Hash,Enums,Magic Methods,我已经定义了一个类,我正试图使其可散列。此外,还有一个枚举,它使用此类的对象作为枚举成员的值 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 stri

我已经定义了一个类,我正试图使其可散列。此外,还有一个枚举,它使用此类的对象作为枚举成员的值

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
语句取消注释,
\uuuuuuuuuuuuuuuu
\uuuuuuuueq\uuuuu
魔术方法被调用用于两个枚举成员值。为什么会这样?这些不是只在散列和相等性检查期间使用吗

此外,如果我将enum类更改为以下内容,那么所有的麻烦都会消失

class Property(Enum):
    cool = Dummy("foo", "cool")
    hot = [Dummy("bar-1", "hot-1"), Dummy("bar-2", "hot-2")]
\uuuu eq\uuuu
魔术方法似乎是为与
属性.cool
相对应的
虚拟对象和与
属性.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'
为foo$cool调用哈希
----
Eq呼吁:
foo$cool
[, ]
----
回溯(最近一次呼叫最后一次):
文件“test.py”,第28行,在
类属性(枚举):
文件“/blah/.local/lib/python2.7/site packages/enum/_init__.py”,第237行,在_new中__
如果canonical_member.value==enum_member.\u value\ux:
文件“test.py”,第19行,在__
返回(self.property是other.property)
AttributeError:“列表”对象没有属性“属性”
为什么会这样?为什么首先要调用神奇的方法,为什么要对类对象和列表调用
\uuuuuuueq\uuuuu


请注意,这只是一个具有代表性的示例,而实际的用例使这种设计——使用值作为可哈希类对象列表的枚举——看起来不那么奇怪。

枚举类正在比较其成员对象值,以查看是否有其他对象的别名。例如,在以下枚举中,
a
b
都表示相同的值,因此只有
a
应显示在成员列表中(别名不显示):

您可以通过查看执行相等性检查的行的源代码来验证这一点:


对于散列,这样做是为了提供枚举成员的按值查找。同样,这可以在

中找到,这回答了所有问题;谢谢因此,枚举成员的值不能是不可散列的可变对象(如列表),可以是。如果该值不可散列,则它只会不包括在按值查找表中,因此尝试按值查找它将遍历成员并检查是否相等
class A(Enum):
    a=1
    b=1