在Dictionary键中对象不被认为是相同的 - 但实现了__eq__

Ale*_*ley 3 python dictionary

以下代码给出了一条错误消息:

    class Test(object):

    def __init__(self, test = 0):
        self.test = test

if __name__ == '__main__':
    t1 = Test(1)
    t2 = Test(2)
    t3 = Test(3)
    t4 = Test(1)
    my_dict = {}
    my_dict[t1] = 1
    my_dict[t2] = 2
    my_dict[t3] = 3

    print(my_dict[t4])

Traceback (most recent call last):
  File "C:\Users\Alexander\Documents\Visual Studio 2015\Projects\PipeProcessTest
\PipeProcessTest\DictionaryKeys.py", line 16, in <module>
    print(my_dict[t4])
KeyError: <__main__.Test object at 0x0000000002F18080>
Run Code Online (Sandbox Code Playgroud)

这是因为python将t1和t4视为不同的对象.但是,当我使用以下代码实现比较运算符' eq '时:

def __eq__(self, other):
        if self.test == other.test:
            return True
        else:
            return False
Run Code Online (Sandbox Code Playgroud)

我收到另一条错误消息,"unhashable type:'Test'"告诉我现在字典不能散列Test对象.我该如何解决这个问题,以便Python能够识别t1和t4是否相同,还能够对Test对象进行哈希处理?

Bre*_*arn 7

你需要__hash__另外实现__eq__.有关如何执行此操作的说明,请参阅文档.要记住的主要事情是比较相等的对象必须具有相同的哈希值.因此,如果您只想通过查看test属性来比较相等性,那么您__hash__还需要仅使用该test属性.正在搜索有关此信息的信息,__hash__并且__eq__还将在此网站上发现许多以前的问题.


gsb*_*eng 6

1. 这是因为python将t1和t4视为不同的对象。但是,当我使用以下代码实现比较运算符“eq”时:

当您在 python 中执行以下操作时....

class Test(object):

    def __init__(self, test = 0):
        self.test = test

if __name__ == '__main__':
    t1 = Test(1)
    t2 = Test(2)
    t3 = Test(3)
    t4 = Test(1)
    my_dict = {}
    my_dict[t1] = 1
    my_dict[t2] = 2
    my_dict[t3] = 3
Run Code Online (Sandbox Code Playgroud)

这意味着您实际上是在尝试创建一个dict以键为Test对象的对象,Python 首先会检查它们是否keys存在hashable

objectPython 中的Any是hashable当它integerobj.__hash__()方法返回任何值时。在 python 中,默认情况下所有用户定义的类都会获得一些哈希值,即id(self).

显然,当你获得id价值时hash,它们看起来会像这个价值8772302607193。因此,如果我们使用这些 id 构建hash表,它可能看起来像这样..

让我们假设 id 是这样的..

id(t1) = 1
id(t2) = 4   # These are just assumptions.
id(t3) = 10  # actual id's are long values.
id(t4) = 20
Run Code Online (Sandbox Code Playgroud)

这就是hash表的构造方式....

    hash     Actual
    value    value  
    ------------------
    | 1    |  t1     |
    ------------------
    | 2    | NULL    |
    ------------------   # Consider that you've respective values are
    | 3    | NULL    |   # here, just for representation I've mentioned
    ------------------   # t1, t2, t3, t4, ..
    | 4    | t2      |
    ------------------
           |
           |
    ------------------
    | 10   |  t3     |
    ------------------
           |
         SO ON
Run Code Online (Sandbox Code Playgroud)

像这样你的hash表被构建,所以当你尝试获得值的t4时候my_dict[t4]。根据假设哈希值为,首先通过调用python 检查 的hash值。t4t4.__hash__()t420

获取哈希值后,20它会检查索引为 20 的哈希表,因为我们没有使用20Python插入任何值只会引发KeyError异常,这就是您KeyError在尝试时得到的原因my_dict[t4]

这里的另一个场景:

如果您尝试覆盖__hash__方法 fTest类并继续执行您在下面所做的相同操作..

class Test(object):

    def __init__(self, test = 0):
        self.test = test
    def __hash__(self):
        self.test       # You are just returning the same value

if __name__ == '__main__':
    t1 = Test(1)
    t2 = Test(2)
    t3 = Test(3)
    t4 = Test(1)
    my_dict = {}
    my_dict[t1] = 1
    my_dict[t2] = 2
    my_dict[t3] = 3
Run Code Online (Sandbox Code Playgroud)

由于我们有overloadedhash 方法返回与初始化相同的值,下面是我们得到的散列值

t1 = 1 , t2 = 2, t3 = 3, t4 = 1
Run Code Online (Sandbox Code Playgroud)

这就是hash当我们有多个值时 table 的样子same hash value

      hash    Actual
      value   value  
      ------------------
      | 1    | [t1,t4] | # List of values for the same hash value.
      ------------------
      | 2    |  t2     |
      ------------------ # Consider that you've respective values are
      | 3    |  t3     | # here, just for representation I've mentioned
      ------------------ # t1, t2, ...
      | 4    |  NULL   |
      ------------------
           |
         SO ON
Run Code Online (Sandbox Code Playgroud)

在这种情况下当您尝试获取时my_dict[t4],如前所述首先检查t4.__hash__()返回的哈希值1。现在 Python dict 检查index1 中的 1hash table并获得多个值[t1, t4]

在这种情况下,__eq__当您有多个具有相同hash value. 你可以像下面这样做来避免这种情况......

class Test(object):
    def __init__(self, test = 0):
        self.test = test
    def __hash__(self):
        return self.test
    def __eq__(self, other):
        return self is other
Run Code Online (Sandbox Code Playgroud)

在您的情况下,您只需要验证self.test值即可获取对象...

class Test(object):

    def __init__(self, test = 0):
        self.test = test
    def __hash__(self):
        return self.test
    def __eq__(self, other):
        return other.test == self.test
Run Code Online (Sandbox Code Playgroud)

这就是您可以管理 dict 值的方式!