python3字典的底层原理以及对hashlib的简单使用

Python3.6以后的字典采用开放地址法解决哈希冲突,通过哈希值对数组长度取余确定索引。字典有序性源于添加元素时的索引记录。hashlib模块提供MD5和SHA256等哈希算法,用于文件哈希、密码保护、完整性校验、数字签名等多种场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

python3.6以后字典的底层原理

在Python3中,字典的底层实现采用了开放定址法和二次探测来解决哈希冲突的问题。具体来说,Python3的字典内部包含了一个哈希表,其中每个元素都是一个"entry"(条目),每个entry都包含了三个元素:键、值和哈希值。在Python3的字典中,哈希值是通过hash()函数计算出来的。

当我们定义一个字典时,python底层会初始化一个二维数组,如下所示

my_dict={}

内存示意图:

indices = [None, None, None, None, None, None, None, None]

entries = []

添加一条数据

my_dict['name'] = 'kingname'


此时的内存示意图

indices = [None, 0, None, None, None, None, None, None]

entries = [[-5954193068542476671, 指向name的指针, 执行kingname的指针]]

可见,底层首先对name进行hash并且对8取余,即 hash(‘name’) % 8,那么计算出的结果作为indices的index(索引),而indices的value(值)就是当前entries的元素个数,这样,entries每次新增元素只需要不断的append就行了。

my_dict['address'] = 'xxx'
my_dict['salary'] = 999999

此时的内存示意图
indices = [1, 0, None, None, None, None, 2, None]

entries = [[-5954193068542476671, 指向name的指针, 执行kingname的指针],
          [9043074951938101872, 指向address的指针,指向xxx的指针],
          [7324055671294268046, 指向salary的指针, 指向999999的指针]
         ]

这也是python3.6以后为什么字典有序的原因,即每次先得到元素在indices的位置,然后通过value得到entries的位置。

hash表怎样解决哈希冲突
  1. 链接法(Separate Chaining):在每个哈希桶中,使用链表等数据结构来存储具有相同哈希值的键值对。当两个键映射到相同的哈希桶时,它们可以被放入同一个链表中,而不是覆盖原始键值对。
  2. 开放地址法(Open Addressing):在开放地址法中,当发生冲突时,可以继续在哈希表中查找下一个空的位置,并将键值对插入到该位置。这可以通过使用一些探测序列来实现,例如线性探测或二次探测,以便在哈希表中寻找下一个可用的位置。

python3.6是使用开放地址来解决地址冲突的问题的。

python hashlib使用

Python中的哈希函数可以对文件进行哈希。可以使用内置的hashlib模块,该模块提供了多种哈希算法,例如MD5、SHA1、SHA256等

1.md5
import hashlib

#使用md5算法对文件进行哈希
def hash_file_md5(filename):
    md5_hash=hashlib.md5()
    with open(filename,'rb') as f:
        for chunk in iter(lambda: f.read(4096),b""):
            md5_hash.update(chunk)
    return md5_hash.hexdigest()

print(hash_file_md5('cpu_mem.log'))   #使用自己的一个日志文件来测试

#output
#dfcdac6710c1528a7d7377a8efddf001

代码解释:

先创建一个md5_hash对象,然后使用open打开文件,使用lambda表达式构造返回读取的数据块,b""表示如果遇到空字符串就停止,然后使用chunk来遍历一个iter对象,最后md5_hash不断更新数据块的hash值,在循环结束后,我们就可以得到整个文件内容的MD5哈希值,即hexdigest。

2.sha256

import hashlib

def hash_file_sha256(filename):
    hash_sha256=hashlib.sha256()
    with open(filename,'rb') as f:
        for chunk in iter(lambda:f.read(4096),b""):
            hash_sha256.update(chunk)
    return hash_sha256.hexdigest()

print(hash_file_sha256('cpu_mem.log')) 

总结:两种hash函数的使用方法大同小异,后续我会学习算法实现的具体细节。

hash算法的特点:
1.不可逆性
2.抗碰撞性

应用:
1.密码保护:用户初次输入密码后,服务器会保存密码的hash值,如md5的值,这样,即使别人盗取密码,也只是盗取其md5值,而由于不可逆性,其不可能知道密码的明文。
2.完整性校验:传送文件时,会先传送文件的md5值,然后当文件到达后,对文件做一次hash,如果得到的md5的值是一样的,则说明文件没有被篡改
3,数字签名:假设有一个程序,可以先对其hash,用户下载时可以自行进行一次hash,如果一样,则没有被更改过,这样可以防止恶意更改文件。
4.云盘秒传:当向云盘传送几个G的文件时,有时候几乎是秒传,因为首先会计算其md5值,如果云盘数据库里面有这个值,说明有数据库里面这个文件,就不需要重新传这个文件了,而是直接使用以及存在的文件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值