id,hash 和 hashlib

看了标题,大家应该知道今天我要讲的内容了,其中 id 和 hash 是内置的两个函数,hashlib 是一个模块,它们的共同点就是给每一个对象一个特定的标志,当然它们也有不同之处。

id

id 函数有一个参数,参数类型没有限制,可以是任意类型(实际上是 object 类型),返回一个对象的身份。这个函数确保参数在同时存在的对象中独一无二,如果是 CPython(底层语言是 C),该函数返回该对象的内存地址。其实 Python 有很多,远远不止一个 CPython,还有 Jython(底层语言是 Java) 和IronPython(底层语言是 C#)等。如果不是 CPython 这个 id 的返回值有什么规律我就不做演示了,大家可以自己尝试,下面我就来演示一下在 CPython 中为什么返回的是内存地址。

首先定义一个列表 a,然后把 a 赋值给 b,此时 b 和 a 应该值相等,如果地址相等的话,那么我修改 b 时,a 也会跟着变化,通过下面的操作,我们可以发现地址是相等的,id(a) 和 id(b) 相等,而且值是一个整数,接下来我们只要做一件事就可以确定这是通过一个算法生成的特定值还是内存中的地址(会变化),其实很简单,我们重新打开一个解释器继续创建同样的对象并且用 id 得到值,如图所示。

很明显,不同的解释器值不一样,所以它返回的是内存地址,而不是由一种算法产生的一个特定的值。

hash

hash 函数有一个参数,参数类型有一点限制,必须是可哈希的类型,返回传入对象的哈希值,两个相等的对象也必然有相等的哈希值。

可哈希类型主要是不可变类型,当然自己定义的类默认也是可哈希的,怎么样自己可以定义不可哈希的类型呢?其实很简单,继承不可哈希的类就完事了。如果我不继承,就想自己手写一个不可哈希的类该怎么办?其实很简单,重写 __eq__ 魔法方法的同时,不去重写 __hash__ 方法,那么这个类就不可哈希。下面我就不做验证了,直接演示一下为什么两个相等对象有着相等的 hash 值。

首先定义字符串 a,然后定义字符串 b,a == b,hash(a) == hash(b),证明完毕。我们发现 hash(a) 返回一个整数,接下来我们证明新开一个解释器,用同样的值再来定义一个字符串 a,看看 hash(a) 是不是还是这个值,如图所示。

这就怪了,按理来说如果值相等 hash 应该也相等才对啊,其实这个说法只能适用于一个解释器,多个解释器这样的说法就行不通了,如果要想在多个解释器保证这种说法正确就不能使用此函数,应该使用 hashlib 模块的函数。下面我们只要验证同一个解释器的两个值相等的对象有不同的地址就行了。

可以发现地址不相等但值相等就有相同的哈希值。

hashlib

为了解决 hash 函数带来的问题,就必须使用模块 hashlib 了,hashlib 提供了很多 hash 算法,其中常用的也就两个——md5 和 sha1,两个算法原理差不多,都是对称加密。这里就以 sha1 为例讲一下。

sha1 函数最多有一个参数,如果有 1 个参数,参数类型必须是字节类型。该函数返回一个 sha1 的哈希对象,如果要获取哈希后的字符串,就还要调用该对象的 hexdigest 方法。下面我就来证明即使解释器不同,只要值相等就会得到相等的哈希后的字符串。

可以发现不同的解释器也可以获得相同的哈希值。

经过上面实验可以得出以下结论,如果要想获得用户输入的哈希值最好使用 hashlib 模块中的函数,因为你服务器的解释器和用户客户端的解释器(假设用户的客户端是 Python 实现的)不是一个解释器,内置的 hash 函数会带来一些问题。

本文分享自微信公众号 - Python机器学习算法说书人(Python-ML-Algorithm),作者:小陈学Python

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-06-02

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Python 装饰器

    我们可以发现这个函数的名字有点长,现在我想给它一个缩写 cop,这该怎么办?很明显我可以直接修改定义的函数名,这是我自己写的函数,我想去改确实可以,但是如果这是...

    不可言诉的深渊
  • 魔法方法(2)

    在学习面向对象程序设计时,我们通常会学到存取方法,它们是名称类似于getHeight和setHeight的方法,用于获取和设置属性(这些属性可能是私有的)。如果...

    不可言诉的深渊
  • 魔法方法(1)

    在Python中,有些名称很特别,开头和结尾都是两个下划线。我们可能用过一些,如__future__。这样的拼写表示名称有特殊意义,因此绝不要在程序中创建这样的...

    不可言诉的深渊
  • 【MATLAB 从零到进阶】day6 MATLAB绘图与可视化

    图形窗口、线条、曲面和注释等都被看作是MATLAB中的图形对象,所有这些图形对象都可以通过一个被称为“句柄值”的东西加以控制,例如可以通过一个线条的句柄值来修改...

    统计学家
  • 狄斯奎诺(dijkstra 模板)

    /*狄斯奎诺算法(dijkstra)<邻接表> */ #include<stdio.h> #include<string.h> #include<stdlib....

    Gxjun
  • 用阻塞队列,再系一次鞋带

    在上篇文章里,通过锁打印资源实现了需求,但是总觉着这个代码不够优雅,然后搞了一个阻塞队列的方式,至少代码上,感觉优雅了很多。

    麒思妙想
  • 蓝桥杯 基础练习 完美的代价

    回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一...

    Debug客栈
  • 入门大爆炸式发展的深度学习,你先要了解这4个最流行框架

    [ 导读 ]对深度学习做出巨大贡献的Yoshua Bengio,他与Yann Lecun和Geofrey Hinton等人在今年3月获得了图灵奖。近几年,深度学...

    数据派THU
  • 如何仅使用TensorFlow C+来训练深度神经网络

    作者|Florian Courtial 译者|Debra 编辑|Emily AI 前线导读:训练神经网络是一件十分复杂,难度非常大的工作,有没有可能让训练的过程...

    企鹅号小编
  • Python Django性能测试与优化指南

    摘要:本文通过一个简单的实例一步一步引导读者对其进行全方位的性能优化。以下是译文。

    用户2337871

扫码关注云+社区

领取腾讯云代金券