Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在字典键中,对象不被认为是相同的,但是_eq____________________________Python_Dictionary - Fatal编程技术网

Python 在字典键中,对象不被认为是相同的,但是_eq___________________________

Python 在字典键中,对象不被认为是相同的,但是_eq___________________________,python,dictionary,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] =

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

    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>

我收到另一条错误消息,“unhabable type:'Test'”告诉我,现在字典无法散列测试对象。如何解决这个问题,使Python能够识别t1和t4是相同的,但也能够对测试对象进行哈希处理?

除了
\uuuuuueq\uucode>之外,还需要实现
\uuuuuuhash\uucode>。有关如何执行此操作的说明,请参见。要记住的主要一点是,比较相等的对象必须具有相同的哈希值。因此,如果您只想通过查看
test
属性来比较相等性,那么您的
\uuuuuuuuuuuuuuuuuuu
也只需要使用
test
属性。搜索有关
\uuuuuuuuuuuuuuu散列和
\uuuueq\uuuuuuuuuuuuuuuuuuuuuuuu
的信息也会在这个网站上发现许多以前的问题。

你只需要返回
方法中的
self.test
,这样你的对象散列值就基于它们的测试属性,所以t1和t4将具有相同的散列值和dict在t1或t4上查找将返回相同的值:

   def __init__(self, test = 0):
        self.test = test
    def __eq__(self, other):
        return self.test == other.test
    def __hash__(self):
        return self.test
如果在
eq
中不需要if/else,您只需返回
self.test==other.test

In [2]: t1 = Test(1)   
In [3]: t2 = Test(2)   
In [4]: t3 = Test(3)   
In [5]: t4 = Test(1)
In [6]:  my_dict = {}    
In [7]: print(t1 == t4)
True   
In [8]: my_dict[t1] = 1    
In [9]: my_dict[t2] = 2    
In [10]: my_dict[t3] = 3
In [11]: print(my_dict[t4])
1

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
这意味着您实际上正在尝试创建一个
dict
,其中键是
Test
对象,Python首先检查
键是否可散列

Python中的任何
对象
在返回
obj的任何
整数
值时都是可哈希的。在python中,默认情况下,所有用户定义的类都会获取一些散列值,即
id(self)

很明显,当你得到
id
值作为
hash
值时,它们看起来像这个值
8772302607193
。因此,如果我们使用这些id构造
哈希表
表,它可能如下所示

id(t1) = 1
id(t2) = 4   # These are just assumptions.
id(t3) = 10  # actual id's are long values.
id(t4) = 20
让我们假设id是这样的

id(t1) = 1
id(t2) = 4   # These are just assumptions.
id(t3) = 10  # actual id's are long values.
id(t4) = 20
这就是
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
像这样,您的
散列
表就被构造出来了,所以当您尝试获取
t4的值时,只需尝试
my_dict[t4]
。根据假设
t4
哈希值为
20
,通过调用
t4.\uu hash\uuuu()
,python首先检查
t4
哈希值

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

这里还有另一个场景:

如果您尝试重写
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

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
由于我们重载了
hash方法以返回与初始化时相同的值,下面是我们得到的hash值

t1 = 1 , t2 = 2, t3 = 3, t4 = 1
这就是当我们有多个具有相同哈希值的值时,
hash
表的外观

      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
在这种情况下,当您尝试获取
my_dict[t4]
时,如前所述,首先检查哈希值
t4。
返回
1
。现在,Python在
哈希表中的
索引
1处进行dict检查,它得到多个值
[t1,t4]

在这种情况下,
\uuuuueq\uuuu
可以帮助您识别具有相同
哈希值的多个值的对象。你可以像下面这样避免这种情况

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
在您的情况下,只需验证
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

这就是如何管理dict值的方法

对于每个人来说,这里有一个相当不错的例子:

class NonComparable(object):
    def __init__(self):
        pass

# Convert a cmp= function into a key= function 
class Comparable(object): 
    def __init__(self, val, hash_lambda, cmp_lambda): 
        self.val = val
        self.hash_lambda = hash_lambda
        self.cmp_lambda = cmp_lambda

    def __hash__(self): 
        return self.hash_lambda(self.val)

    def __eq__(self, other): 
        return self.cmp_lambda(self.val, other.val) == 0
        # return id(self) == id(other)

# driver code 
if __name__ == "__main__": 
    # __hash__ is available even if you don't implement it, it'd return hash(nc1), not id(nc1). hash() isn't available by default.
    # Note also,
    # id(123) = an integer
    # hash(456) = 456
    # So, hash(id(nc1)) = id(nc1)
    nc1 = NonComparable()
    nc1_hash = nc1.__hash__()

    nc2 = NonComparable()
    nc2_hash = nc2.__hash__() 

    moduli = 2
    hash_lambda = lambda x : x * x
    cmp_lambda_by_val = lambda x,y : x == y
    cmp_lambda_by_objid = lambda x,y : id(x) == id(y)

    c1 = Comparable(5, hash_lambda, cmp_lambda_by_val) # hash = 5*5 = 25
    c2 = Comparable(8, hash_lambda, cmp_lambda_by_val) # hash = 8*8 = 64

    # same hash code (To simulate hash collision), but compare by Equal based on id(obj)
    c3 = Comparable(5, hash_lambda, cmp_lambda_by_objid) 
    c4 = Comparable(5, hash_lambda, cmp_lambda_by_objid) 

    dict1 = {}
    dict1[nc1] = nc1
    dict1[nc2] = nc2
    res = dict1[nc1]

    dict2 = {}
    dict2[c1] = c1
    dict2[c2] = c2
    res = dict2[c1]

    dict3 = {}
    dict3[c3] = c3
    dict3[c4] = c4
    res = dict3[c3]
    # id(c3) == id(res)
    pass
参考资料


你知道你从来没有把
t4
放在你的字典里,对吧?@MorganThrapp,我想这就是问题所在,如何用
t4
进行查找以返回t1,因为它们都是用
1
初始化的@PadraicCunningham ahh,这稍微有点道理。我也不明白反对票——你的解决方案应该有效。其实布伦巴恩也说过同样的话。也许是因为你没有解释背后的原因?(只是猜测)。@TigerhawkT3,是的,修正了。@Iserni,可能是这样,但dv几乎是瞬间的,所以可能有其他力量在起作用!