Python 中的“hashable”是什么意思?

2024-12-19 09:24:00
admin
原创
143
摘要:问题描述:在 Python 代码中,对象可哈希到底是什么意思?解决方案 1:来自Python 词汇表:如果一个对象的哈希值在其生命周期内永远不会改变(需要一种__hash__()方法),并且可以与其他对象进行比较(需要__eq__()或__cmp__()方法),则该对象是可哈希的。比较相等的可哈希对象必须具有...

问题描述:

在 Python 代码中,对象可哈希到底是什么意思?


解决方案 1:

来自Python 词汇表:

如果一个对象的哈希值在其生命周期内永远不会改变(需要一种__hash__()方法),并且可以与其他对象进行比较(需要__eq__()__cmp__()方法),则该对象是可哈希的。比较相等的可哈希对象必须具有相同的哈希值。

可哈希性使得对象可用作字典键和集合成员,因为这些数据结构在内部使用哈希值。

Python 的所有不可变内置对象都是可哈希的,而可变容器(如列表或字典)则不是。默认情况下,作为用户定义类的实例的对象是可哈希的;它们进行比较都不相等,并且它们的哈希值是它们的id()

解决方案 2:

这里的所有答案都对 Python 中的可哈希对象进行了很好的解释,但我认为首先需要理解“哈希”这个术语。

散列是计算机科学中的一个概念,用于创建高性能、伪随机访问数据结构,其中需要快速存储和访问大量数据。

例如,如果您有 10,000 个电话号码,并且想要将它们存储在一个数组中(这是一种将数据存储在连续的内存位置并提供随机访问的顺序数据结构),但您可能没有所需数量的连续内存位置。

因此,您可以改用大小为 100 的数组,并使用哈希函数将一组值映射到相同的索引,这些值可以存储在链接列表中。这提供了与数组类似的性能。

现在,哈希函数可以简单到用数字除以数组的大小,然后将余数作为索引。

有关更多详细信息,请参阅https://en.wikipedia.org/wiki/Hash_function

这里还有另一个很好的参考: http: //interactivepython.org/runestone/static/pythonds/SortSearch/Hashing.html

解决方案 3:

任何不可变的东西(可变意味着可能会改变)都可以被哈希化。除了要查找的哈希函数(如果某个类有它),例如dir(tuple)查找__hash__方法,下面是一些示例

#x = hash(set([1,2])) #set unhashable
x = hash(frozenset([1,2])) #hashable
#x = hash(([1,2], [2,3])) #tuple of mutable objects, unhashable
x = hash((1,2,3)) #tuple of immutable objects, hashable
#x = hash()
#x = hash({1,2}) #list of mutable objects, unhashable
#x = hash([1,2,3]) #list of immutable objects, unhashable

不可变类型列表:

int, float, decimal, complex, bool, string, tuple, range, frozenset, bytes

可变类型列表:

list, dict, set, bytearray, user-defined classes

解决方案 4:

根据我的 Python 术语表,当您创建可哈希的对象实例时,还会根据实例的成员或值计算出一个不可更改的值。例如,该值可以用作字典中的键,如下所示:

>>> tuple_a = (1, 2, 3)
>>> tuple_a.__hash__()
2528502973977326415
>>> tuple_b = (2, 3, 4)
>>> tuple_b.__hash__()
3789705017596477050
>>> tuple_c = (1, 2, 3)
>>> tuple_c.__hash__()
2528502973977326415
>>> id(tuple_a) == id(tuple_c)  # tuple_a and tuple_c same object?
False
>>> tuple_a.__hash__() == tuple_c.__hash__()  # hash of tuple_a and tuple_c same value?
True
>>> dict_a = {}
>>> dict_a[tuple_a] = 'hiahia'
>>> dict_a[tuple_c]
'hiahia'

tuple_a我们可以发现和 的哈希值tuple_c相同,因为它们有相同的成员。当我们用 作tuple_a键时dict_a,我们可以发现 的值dict_a[tuple_c]是相同的,这意味着,当它们用作字典中的键时,它们返回相同的值,因为它们的哈希值相同。对于那些不可哈希的对象,该方法__hash__定义为None

>>> type(dict.__hash__) 
<class 'NoneType'>

我猜这个哈希值是在实例初始化时计算的,而不是以动态方式计算的,这就是为什么只有不可变对象才是可哈希的。希望这能有所帮助。

解决方案 5:

Hashable = 能够被散列。

好的,什么是哈希?哈希函数是一种接受对象(例如字符串“Python”)并返回固定大小代码的函数。为简单起见,假设返回值是一个整数。

当我在 Python 3 中运行 hash('Python') 时,我得到的结果为 5952713340227947791。不同版本的 Python 可以自由更改底层哈希函数,因此您可能会得到不同的值。重要的是,无论我运行 hash('Python') 多少次,我都会使用相同版本的 Python 获得相同的结果。

但是 hash('Java') 返回 1753925553814008565。因此,如果我要散列的对象发生变化,结果也会发生变化。另一方面,如果我要散列的对象没有变化,那么结果保持不变。

这为什么重要?

例如,Python 字典要求键是不可变的。也就是说,键必须是不会改变的对象。Python 中的字符串是不可变的,其他基本类型(int、float、bool)也是如此。元组和冻结集也是不可变的。另一方面,列表不是不可变的(即,它们是可变的),因为您可以更改它们。同样,字典也是可变的。

因此,当我们说某个东西是可哈希的时,我们的意思是它是不可变的。如果我尝试将可变类型传递给 hash() 函数,它将失败:

>>> hash('Python')
1687380313081734297
>>> hash('Java')
1753925553814008565
>>>
>>> hash([1, 2])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> hash({1, 2})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'
>>> hash({1 : 2})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>>
>>> hash(frozenset({1, 2}))
-1834016341293975159
>>> hash((1, 2))
3713081631934410656

解决方案 6:

在 Python 中,任何不可变对象(例如整数、布尔值、字符串、元组)都是可哈希的,这意味着其值在其生命周期内不会改变。这允许 Python 创建一个唯一的哈希值来标识它,字典可以使用它来跟踪唯一键,集合可以使用它来跟踪唯一值。

这就是为什么 Python 要求我们作为字典中的键使用不可变数据类型的原因。

解决方案 7:

在 Python 中,这意味着对象可以是集合的成员,以便返回索引。也就是说,它们具有唯一的标识/id。

例如在python3.3中:

数据结构列表不可哈希,但数据结构元组可哈希。

解决方案 8:

让我给你一个实际的例子来理解 Python 中的可哈希对象。我以 2 个元组为例。元组中的每个值都有一个唯一的哈希值,该值在其生命周期内永远不会改变。因此,基于这个值,可以完成两个元组之间的比较。我们可以使用 Id() 获取元组元素的哈希值。

2 个元组之间的比较两个元组之间的等价性

解决方案 9:

作为对其他答案的补充:Python 词汇表说“默认情况下,作为用户定义类的实例的对象是可哈希的。”但它还说“比较相等的可哈希对象必须具有相同的哈希值。”。

因此,如果您实现__eq__-Method 而不实现__hash__-Method,您的对象将不可哈希。否则,从中派生哈希值id()并不能保证两个比较相等的对象会生成相同的哈希值(id(a) != id(b)a == b

>>> class Foo(object):
...     def __eq__(self, other): pass
... 
>>> 
>>> class Bar(object):
...     pass
... 
>>> f = Foo()
>>> b = Bar()
>>> 
>>> hash(f)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'Foo'
>>> hash(b)
8758325844794

解决方案 10:

要从头开始创建哈希表,所有值都必须设置为“无”,并在需要时进行修改。可哈希对象是指可修改的数据类型(字典、列表等)。另一方面,集合一旦分配就无法重新初始化,因此集合是不可哈希的。而 set() 的变体 — — frostset() — — 是可哈希的。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1950  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1439  
  在企业运营过程中,跨部门协作效率的高低直接影响着项目的推进速度与质量,进而关乎企业的整体竞争力。PLM(产品生命周期管理)项目管理软件作为一种强大的工具,正逐渐在提升跨部门协作效率方面发挥着关键作用。它打破了部门之间的信息壁垒,优化了业务流程,为企业各部门之间的协同工作提供了有力支持。PLM项目管理软件打破信息壁垒信息...
plm合规性管理   17  
  PLM(Product Lifecycle Management)软件,即产品生命周期管理软件,旨在助力企业对产品从概念设计到退役处理的全生命周期进行有效管理。通过整合产品数据、流程以及人员,PLM软件能显著提升企业的创新能力、生产效率并降低成本。然而,PLM软件的实施并非易事,众多企业在落地过程中遭遇诸多挑战。要实现...
国内plm系统排名   19  
  研发过程的可视化对于企业提升效率、保障项目顺利推进至关重要。PLM(产品生命周期管理)系统作为整合产品全生命周期信息的重要工具,与甘特图相结合,能为研发过程可视化提供强大支持。通过对PLM系统支撑下甘特图的优化展现,可以让项目团队成员、管理层等清晰了解研发进度、资源分配等关键信息,从而做出更科学的决策。接下来,我们将详...
plm系统主要干什么的   16  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用