【问题标题】:Interaction of a hashable class with Enum in PythonPython中可散列类与枚举的交互
【发布时间】:2017-04-09 23:05:39
【问题描述】:

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

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__ 魔术方法似乎是为对应于Property.coolDummy 对象和对应于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__

请注意,这只是一个代表性示例,真实的用例使这种设计——将值作为可散列类对象列表的枚举——显得不那么奇怪。

【问题讨论】:

    标签: python python-2.7 hash enums magic-methods


    【解决方案1】:

    Enum 类正在比较它的成员对象值以查看是否有其他对象的别名。例如,在下面的 Enum 中,ab 代表相同的值,因此只有 a 应该出现在成员列表中(别名不会):

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

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

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

    中找到

    【讨论】:

    • 这回答了一切;谢谢。因此,枚举成员的值不能是可变对象,如列表,它是不可散列的。
    • 他们可以。如果该值不是可散列的,它只会不包含在按值查找表中,因此尝试按值查找它将遍历成员并检查是否相等
    猜你喜欢
    • 1970-01-01
    • 2020-11-17
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 2014-10-19
    • 2012-09-16
    • 2016-05-10
    相关资源
    最近更新 更多