Python 中的哈希表
Python 中的哈希表:对字典的理解
有没有想过,Python中的字典为什么这么高效稳定。原因是他是建立在hash表上。了解Python中的hash表有助于更好的理解Python,因为Python中字典无处不在。
hash 函数
哈希函数是一个可以将任意长度的数据块映射到固定长度的值,这个步骤称为hash,也就是散列。
hash 函数有三个主要的特征:
- 计算迅速:计算一个数据块的hash值非常快
- 确定性:相同用字符串会产生相同的hash值
- 结果固定长度:不管输入的是,一个字节还是十个字节,或者上万个字节,结果总是预先确定的长度。
另一个特征在hash函数中非常普遍,即他们是单方向的:通过函数实现后,原始数据丢失了,我们可以通过字符串得到一个hash值,但不能通过一个hash也就是散列得到原始的字符串(因为有对数据降维的方法会造成数据的丢失)。这种特性并不是对所有hash函数的强制性规定,但是当需要加密安全时,这种性质还是挺好用的。
一些比较受欢迎的算法包括:MD5、SHA-1、SHA-2,NTLM.
关于hash的一些使用方法
很多东西都依赖hash,hash表就是其中一例,另一些用法是出于加密和的原因
一个具体的例子就是当你尝试从网上下载开源软件时。通常你都会发现一个关联文件,这个关联文件就是这个文件签名。这个签名仅仅是源文件的散列值它非常有用,你为你可以自己通过计算下载好的文件的散列值并与网站上提供的签名进行对比,这样就可以确认你自己下载的文件没有损坏。
另一种用法是存储用户的密码。你有没有问过你自己,当你忘掉了一个网站的登录密码的时候,你还想从这个网站上恢复登录,它只会让你重新确定一个新的登录密码而不是给你原来你选择的密码,这是因为网站并不会储存你完整的密码,而是你密码的hash值。
这么做是出于安全因素,因为如果黑客搞到了数据库的权限,他们不会知道你真实的密码,而是仅仅得到你密码的哈希值,又因为哈希函数是单向的,他们根本不可能从哈希值得到你的密码
Python 里的hash()函数
Python 中含有内置的函数去给对象生成哈希值,也就是hash()函数,这个函数将一个对象作为输入,返回一个整数的hash值。
内部的,这个函数涉及到.\__hash\__()这个输入对象的方法,所以呢,如果你想使你的自定义类可哈希化,你需要做的是实现.\__hash__()这个方法返回出一个整数,这个整数是基于你的对象的内部状态决定的。
先开始一些基本的小例子,先对数值进行散列
>>> hash(1)
1
>>> hash(10)
10
>>> hash(10.00)
10
>>> hash(10.01)
230584300921368586
>>> hash(-10.01)
-230584300921368586
如果你好奇为什么这些hash值看起来有不同的长度,请记住在Python中hash()函数返回的是整数对象,他们都会在标准的64位Python解释器中通过24字节呈现。
正如你可以看到的,整数的哈希值默认的就是它本身,不管你哈希的数据类型是什么,所以整数1和浮点数1.0哈希值都是1.
这个有什么特殊的么,这个展示了你之前学到的知识,也就是hash函数经常是单向的函数,如果两个不同的对象具有相同的hash值,根本不可能做反向工程,也就是从hash值返回到原始的对象,这也就使得被hash的原始数据类型的信息被丢失。
另几个有趣的可以关注的hash事情是,小数的散列值不同于它本身,负数具有负的哈希值。还有一点,就是如果两个对象具有相同的哈希值,称为哈希碰撞。
哈希一个字符串不同于对数值进行哈希。
>>> hash("Bad Behaviour")
7164800052134507161
DOS攻击(DOS代表拒绝服务)是指攻击者故意耗尽计算机系统的资源,使系统不再能够向客户端提供服务的攻击。在Scott Crosby演示的这个攻击的具体案例中,攻击可能会使目标系统充斥大量的数据,这些数据的哈希冲突导致目标系统使用更多的计算能力来解决冲突。
Python中可以hash的数据类型
在Python中,仅仅只有不可变数据类型可以被hash,然而每个自定义的对象在Python中都可以被hash,默认的他们的hash值是由他们的id派生的。也就意味着,同一个类的两个不同实例,默认的是得到不同的hash值
>>> class Car():
... velocity = 0
... direction = 0
... damage = 0
...
>>> first_car = Car()
>>> second_car = Car()
>>> hash(first_car)
274643597
>>> hash(second_car)
274643604
哈希表
现在你知道了什么是哈希函数,现在可以检测哈希表,哈希表是一个数据结构可以储存一堆键值对。
在哈希表中,键值对的所有建必须是可以哈希的,因为存储的对是通过使用其键的散列索引的。哈希表十分有用,Hash tables are very useful because the average number of instructions that are necessary to lookup an element of the table is independent of the number of elements stored in the table itself.哈希表非常有用,因为查找表中某个元素所需的平均指令数量与表中存储的元素数量无关,这就表明了不管你的表增长到成百上千次,查找特定元素的速度不会受到影响。
哈希表通常是通过创建可变数量的存储桶来实现的,这些存储桶将包含您的数据,并通过哈希它们的键对这些数据进行索引。键的散列值将确定用于特定数据段的正确存储桶。
import pprint
class Hashtable:
def __init__(self, elements):
self.bucket_size = len(elements)
self.buckets = [[] for i in range(self.bucket_size)]
self._assign_buckets(elements)
def _assign_buckets(self, elements):
for key, value in elements:
hashed_value = hash(key)
index = hashed_value % self.bucket_size
self.buckets[index].append((key, value))
def get_value(self, input_key):
hashed_value = hash(input_key)
index = hashed_value % self.bucket_size
bucket = self.buckets[index]
for key, value in bucket:
if key == input_key:
return(value)
return None
def __str__(self):
return pprint.pformat(self.buckets) # here pformat is used to return a printable representation of the object
if __name__ == "__main__":
capitals = [
('France', 'Paris'),
('United States', 'Washington D.C.'),
('Italy', 'Rome'),
('Canada', 'Ottawa')
]
hashtable = Hashtable(capitals)
print(hashtable)
print(f"The capital of Italy is {hashtable.get_value('Italy')}")
Moreover, the more you increase the number of buckets you will handle, the more space you will waste. To test this you can simply change the bucket size of your previous example using a number of buckets that is two times the length of the input list:
此外,处理的桶数增加越多,浪费的空间就越多。要测试这一点,只需使用输入列表长度的两倍的桶数来更改上一个示例的桶大小
两个散列值发生碰撞,将会存储到同一个桶中,因为冲突不可避免,实现一个哈希表就得有一个解决冲突的方法。
通常在哈希表解决冲突的常用策略是:
- open addressing 开放寻址法
- separate chaining 链地址法
连地址法是您在上面的示例中已经实现的,它由使用另一个数据结构在同一个bucket中创建一个值链组成。在那个示例中,您使用了一个嵌套列表,当在超额占用的bucket中查找特定值时,必须对该列表进行完全扫描。
在开放寻址策略中,如果您应该使用的bucket是忙碌的,那么您只需继续搜索要使用的新bucket。要实现这个解决方案,您需要对为新元素分配bucket的方式和检索键值的方式进行一些更改。从assign buckets()函数开始,您必须使用默认值初始化您的bucket,并且如果您应该使用的bucket已经被占用,则继续寻找空的bucket
Dictionaries in Python are built using hash tables and the **open addressing** collision resolution method.
Python 中的哈希表的更多相关文章
- 【转】实习小记-python中可哈希对象是个啥?what is hashable object in python?
[转]实习小记-python中可哈希对象是个啥?what is hashable object in python? 废话不多说直接祭上python3.3x的文档:(原文链接) object.__ha ...
- [PHP内核探索]PHP中的哈希表
在PHP内核中,其中一个很重要的数据结构就是HashTable.我们常用的数组,在内核中就是用HashTable来实现.那么,PHP的HashTable是怎么实现的呢?最近在看HashTable的数据 ...
- 实习小记-python中不可哈希对象设置为可哈希对象
在这篇之前,我又专门翻译过官方python3.3的可哈希对象文档,大家可以先参考一下: 实习小记-python中可哈希对象是个啥?what is hashable object in python? ...
- Delphi 中的哈希表: THashedStringList
转自万一博客 Delphi 中的哈希表: THashedStringList unit Unit1; interface uses Windows, Messages, SysUtils, Var ...
- 实习小记-python中可哈希对象是个啥?what is hashable object in python?
废话不多说直接祭上python3.3x的文档:(原文链接) object.__hash__(self) Called by built-in function hash() and for opera ...
- python数据结构之哈希表
哈希表(Hash table) 众所周知,HashMap是一个用于存储Key-Value键值对的集合,每一个键值对也叫做Entry.这些个键值对(Entry)分散存储在一个数组当中,这个数组就是Has ...
- 数据结构与算法Python版 熟悉哈希表,了解Python字典底层实现
Hash Table 散列表(hash table)也被称为哈希表,它是一种根据键(key)来存储值(value)的特殊线性结构. 常用于迅速的无序单点查找,其查找速度可达到常数级别的O(1). 散列 ...
- OVS 中的哈希表: shash
shash出现在OVS的代码中,定义如下: struct hmap_node { size_t hash; struct hmap_node * next; }; struct ...
- Freemarker 中的哈希表(Map)和序列(List)
freemarlker中的容器类型有: 哈希表:是实现了TemplateHashModel或者TemplateHashModelEx接口的java对象,经常使用的实现类是SimpleHash,该类实现 ...
随机推荐
- rados put striper功能的调试
前言 之前对于striper这个地方的功能并没研究太多,只是知道这个里面可以以条带方式并行的去写对象,从而加大并发性来提高性能,而默认的条带数目为1,也就是以对象大小去写,并没有条带,所以不是很好感觉 ...
- Golang中make的使用
内建函数 make 用来为 slice,map 或 chan 类型分配内存和初始化一个对象(注意:只能用在这三种类型上),跟 new 类似,第一个参数也是一个类型而不是一个值,跟 new 不同的是,m ...
- 解决NUC972使用800*480屏幕时,tslib触摸屏校准时,坐标不对称问题
1.ADC_CONF寄存器中的ADCSAMPCNT的值,设置计数器值以延长ADC起始信号周期以获得更多采样精确转换的时间 2.内核驱动配置好触摸屏ADC的驱动后,调整autoconfig.h中的CON ...
- spring boot和spring cloud的区别
Java中说到微服务肯定离不开Spring Boot和Spring Cloud,这两者到底有什么关系,什么是微服务,如果单纯的说SpringBoot,SpringCloud,都是不准确的,那应该怎么回 ...
- Java并发编程 - Runnbale、Future、Callable 你不知道的那点事(二)
Java并发编程 - Runnbale.Future.Callable 你不知道的那点事(一)大致说明了一下 Runnable.Future.Callable 接口之间的关系,也说明了一些内部常用的方 ...
- kali 更新msf
用leafpad打开,方便复制粘贴 leafpad /etc/apt/sources.list 然后复制下面的源覆盖原本的 deb http://mirrors.ustc.edu.cn/kali ka ...
- Python:利用Entrez库筛选下载PubMed文献摘要
一个不是学生物的孩子来搞生物,当真是变成了一块废铁啊,但也是让我体会到了一把生物信息的力量. 废话不多说,开整! 任务:快速高效从PubMed上下载满足条件的文献PMID.标题(TI).摘要(AB). ...
- Java8用了这么久了,Stream 流用法及语法你都知道吗?
1.简介 Stream流 最全的用法Stream 能用来干什么?用来处理集合,通过 使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询,Stream API 提供了一 ...
- 使用FL Studio来制作停顿的效果
停顿效果是一种在音乐创作中非常常用的音效,它能起到缓冲的作用,而且能使这段旋律更具节奏感,在比较激情的歌曲中尤为常见.例如知名歌手王力宏演唱的<火力全开>中就使用了停顿效果,为歌曲加了不少 ...
- ABBYY FineReader 15 中保存和导出PDF文档的小细节
运用ABBYY FineReader OCR文字识别软件,用户能将各种格式的PDF文档保存为新的PDF文档.PDF/A格式文档,以及Microsoft Word.Excel.PPT等格式.在保存与导出 ...