当前位置:  开发笔记 > 编程语言 > 正文

hash()和id()之间的区别

如何解决《hash()和id()之间的区别》经验,为你挑选了2个好方法。

我有两个用户定义的对象,比如说ab.
这两个对象都具有相同的hash值.
然而,id(a)并且id(b)是不平等的.

此外,

>>> a is b
False
>>> a == b
True

从这个观察中,我可以推断出以下情况吗?

不相等的对象可能具有相同的hash值.

等于对象需要具有相同的id值.

无论何时obj1 is obj2调用,id都会比较两个对象的值,而不是它们的hash值.

Blckknght.. 34

有三个概念,试图理解的时候把握id,hash以及==is运营商:身份,价值哈希值.并非所有对象都有三个.

    所有对象都有一个标识,尽管在某些情况下甚至可能会有点滑.该id函数返回一个对应于对象标识的数字(在cpython中,它返回对象的内存地址,但其他解释器可能返回其他内容).如果两个对象(同时存在)具有相同的标识,则它们实际上是对同一对象的两个引用.该is运营商的身份进行比较的项目,a is b相当于id(a) == id(b).

    当您处理在其实现中某处缓存的对象时,身份可能会有点混乱.例如,cpython中的小整数和字符串的对象在每次使用时都不会重新生成.相反,现有对象会在需要时返回.您不应该在代码中依赖于此,因为它是cpython的实现细节(其他解释器可能以不同方式执行或根本不执行).

    所有对象也有一个,虽然这有点复杂.某些对象除了其标识之外没有其他有意义的值(因此,在某些情况下,标识可能是同义的).值可以定义为==运算符比较的值,因此任何时候a == b,您都可以说a并且b具有相同的值.容器对象(如列表)具有由其内容定义的值,而其他一些对象将具有基于其属性的值.不同类型的对象有时可以具有相同的值,如数字:( 由于历史原因,0 == 0.0 == 0j == decimal.Decimal("0") == fractions.Fraction(0) == False是的,bools是Python中的数字).

    如果类没有定义__eq__方法(实现==运算符),它将继承默认版本,object并且它的实例将仅通过它们的标识进行比较.当其他相同的实例可能具有重要的语义差异时,这是适当的.例如,连接到同一主机的同一端口的两个不同的套接字需要区别对待,如果一个是获取HTML网页而另一个是获取从该页面链接的图像,因此它们没有相同的值.

    除了值之外,一些对象具有哈希值,这意味着它们可以用作字典键(并存储在sets中).该函数hash(a)返回对象a的哈希值,这是一个基于对象值的数字.对象的哈希值必须在对象的生命周期内保持不变,因此只有当一个对象的值是不可变的时(或者因为它基于对象的标识,或者因为它基于对象的内容),它才有可能是可清除的.对象本身是不可变的).

    多个不同的对象可能具有相同的哈希值,但设计良好的哈希函数将尽可能避免这种情况.在字典中存储具有相同散列的对象比存储具有不同散列的对象的效率低得多(每个散列冲突需要更多工作).默认情况下,对象是可清除的(因为它们的默认值是它们的标识,它是不可变的).如果__eq__在自定义类中编写方法,Python将禁用此默认哈希实现,因为您的__eq__函数将为其实例定义值的新含义.__hash__如果你希望你的类仍然可以清洗,你还需要编写一个方法.如果您从hashable类继承但不希望自己是hasable,则可以__hash__ = None在类体中设置.


Alex Riley.. 6

不等的对象可能具有相同的哈希值.

是的,这是真的.一个简单的例子是hash(-1) == hash(-2)在CPython中.

等于对象需要具有相同的id值.

一般来说,这不是假的.@chepner注意到的一个简单的例子是,5 == 5.0但是id(5) != id(5.0).

无论何时obj1 is obj2调用,都会比较两个对象的id值,而不是它们的哈希值.

是的,这是真的.is比较id对象的相等性(在CPython中它是对象的内存地址).通常,这与对象的哈希值无关(对象甚至不需要可哈希).



1> Blckknght..:

有三个概念,试图理解的时候把握id,hash以及==is运营商:身份,价值哈希值.并非所有对象都有三个.

    所有对象都有一个标识,尽管在某些情况下甚至可能会有点滑.该id函数返回一个对应于对象标识的数字(在cpython中,它返回对象的内存地址,但其他解释器可能返回其他内容).如果两个对象(同时存在)具有相同的标识,则它们实际上是对同一对象的两个引用.该is运营商的身份进行比较的项目,a is b相当于id(a) == id(b).

    当您处理在其实现中某处缓存的对象时,身份可能会有点混乱.例如,cpython中的小整数和字符串的对象在每次使用时都不会重新生成.相反,现有对象会在需要时返回.您不应该在代码中依赖于此,因为它是cpython的实现细节(其他解释器可能以不同方式执行或根本不执行).

    所有对象也有一个,虽然这有点复杂.某些对象除了其标识之外没有其他有意义的值(因此,在某些情况下,标识可能是同义的).值可以定义为==运算符比较的值,因此任何时候a == b,您都可以说a并且b具有相同的值.容器对象(如列表)具有由其内容定义的值,而其他一些对象将具有基于其属性的值.不同类型的对象有时可以具有相同的值,如数字:( 由于历史原因,0 == 0.0 == 0j == decimal.Decimal("0") == fractions.Fraction(0) == False是的,bools是Python中的数字).

    如果类没有定义__eq__方法(实现==运算符),它将继承默认版本,object并且它的实例将仅通过它们的标识进行比较.当其他相同的实例可能具有重要的语义差异时,这是适当的.例如,连接到同一主机的同一端口的两个不同的套接字需要区别对待,如果一个是获取HTML网页而另一个是获取从该页面链接的图像,因此它们没有相同的值.

    除了值之外,一些对象具有哈希值,这意味着它们可以用作字典键(并存储在sets中).该函数hash(a)返回对象a的哈希值,这是一个基于对象值的数字.对象的哈希值必须在对象的生命周期内保持不变,因此只有当一个对象的值是不可变的时(或者因为它基于对象的标识,或者因为它基于对象的内容),它才有可能是可清除的.对象本身是不可变的).

    多个不同的对象可能具有相同的哈希值,但设计良好的哈希函数将尽可能避免这种情况.在字典中存储具有相同散列的对象比存储具有不同散列的对象的效率低得多(每个散列冲突需要更多工作).默认情况下,对象是可清除的(因为它们的默认值是它们的标识,它是不可变的).如果__eq__在自定义类中编写方法,Python将禁用此默认哈希实现,因为您的__eq__函数将为其实例定义值的新含义.__hash__如果你希望你的类仍然可以清洗,你还需要编写一个方法.如果您从hashable类继承但不希望自己是hasable,则可以__hash__ = None在类体中设置.



2> Alex Riley..:

不等的对象可能具有相同的哈希值.

是的,这是真的.一个简单的例子是hash(-1) == hash(-2)在CPython中.

等于对象需要具有相同的id值.

一般来说,这不是假的.@chepner注意到的一个简单的例子是,5 == 5.0但是id(5) != id(5.0).

无论何时obj1 is obj2调用,都会比较两个对象的id值,而不是它们的哈希值.

是的,这是真的.is比较id对象的相等性(在CPython中它是对象的内存地址).通常,这与对象的哈希值无关(对象甚至不需要可哈希).


第二个断言的反例:`5 == 5.0` vs`id(5)== id(5.0)`.
@KshitijSaraogi再次尝试`a = []`和`b = []`; `id([])== id([])`的事实是因为两个空列表对象不需要同时存在,因此id可以被回收.
推荐阅读
周扒pi
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有