【问题背景】我自定义了Object类型,在用set()进行判重的时候发现重载了__eq__不起作用,总是认为不同的。

【问题原因】当自定义的Object作为set()集合元素时,由于set 属于哈希算法数据结构,因此判重时首先会判断hash,只有当hash相同时才会继续调用__eq__来判重。其他哈希数据结构也如此。

1 .魔法方法__hash__调用时机

请注意这个 __hash__魔法方法:

(1)被内置函数hash()调用

(2)hash类型的集合对自身成员的hash操作:set(), frozenset([iterable]), dict(**kwarg)

2 应用场景举例

2.1 仅用到__eq__判等,无需重载__hash__

当Object间使用判等符号来比对时仅会调用__eq__,这个时候不需要重载__hash__就能得到正确结果:

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
class Student(object):def __init__(self, name, age):self._name = nameself._age = agedef __hash__(self):print 'Call __hash__'def __eq__(self, other):print 'Call __eq__'if not isinstance(other, Student):return Falsereturn self._name == other._name and self._age == other._ageif __name__ == '__main__':s1 = Student('aa', 20)s2 = Student('aa', 20)s3 = Student('bb', 21)print s1 == s2print s1 == s3

2.2 哈希结构体的比对策略

在Python3.X系列版本中,如果仅自定义__eq__而没有定义__hash__,那么该Object无法作为哈希数据结构(set、frozenset、dict)元素。因为此时自动让__hash__返回None;

在Python2.X系列版本中,如果仅自定义__eq__而没有定义__hash__,那么仍然可以作为哈希数据结构(set、frozenset、dict)元素,此时会导致比对存在BUG,原因如下:

(1)哈希结构体首先调用__hash__比对Object,默认的哈希值生成是不一样的(与地址有关),因此总会判断两个Object不相等,哪怕内部赋值都一样也不行;

(2)哈希结构体在__hash__相等的情况下,会继续调用__eq__比对。

class Student(object):def __init__(self, name, age):self._name = nameself._age = agedef __hash__(self):print 'Call __hash__'return hash(self._name + str(self._age))  # 请注意这里一定要返回hash值,否则None报错def __eq__(self, other):print 'Call __eq__'if not isinstance(other, Student):return Falsereturn self._name == other._name and self._age == other._ageif __name__ == '__main__':s1 = Student('aa', 20)s2 = Student('aa', 20)s3 = Student('bb', 21)test_set = set()test_set.add(s1)print s2 in test_set    # Trueprint s3 in test_set    # False

Python 中的hash相关推荐

  1. Python中Hash值计算的学习笔记

    对于Hash算法的介绍,我们引用博文<Hash算法(含python实现) - yucen>中的介绍: 哈希(hash)也翻译作散列.Hash算法,是将一个不定长的输入,通过散列函数变换成一 ...

  2. Python操作Redis中的hash

    Redis 数据库hash数据类型是一个string类型的key和value的映射表,适用于存储对象.Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿).  Python的re ...

  3. [转载] Python中 hash去重

    参考链接: Python hash() 现在有3000条数据,需要插入到数据库中去,使用的是对链接进行MD5加密, hashcode = md5(str(item_url)) 然后在数据库中设置 ha ...

  4. Python中hash算法

    文章目录 简介 概念 特点 hash有哪些 算法碰撞 加盐防碰撞 加密 hashlib 主要方法 特有方法 使用方法 加盐 crypt 主要方法 使用说明 应用 密码加密 应用一致性校验 简介 概念 ...

  5. Python:python中的可变类型和不可变类型

    Python的基本数据类型大致可分为6类: 1.Number(数字)(bool布尔类型.int整型.float浮点型.complex复数等都归为Number数字类型) 2. String(字符串) 3 ...

  6. 在python中定义类时、运算符重载_自定义 Python 类中的运算符和函数重载(上)...

    如果你对 Python 中的str对象使用过 + 或 * 运算符,你一定注意到了它的操作与 int 或 float 类型的区别: 你可能想知道同一内置运算符或函数如何对不同类对象进行不同操作的.这分别 ...

  7. 通过命令行在Python中测试以太坊RPC客户端

    2019独角兽企业重金招聘Python工程师标准>>> 在这个笔记中,我将使用Python命令行测试以太坊的RPC客户端,准备好狂敲键盘吧.过程中有关JSON RPC的更多信息,可以 ...

  8. python中append函数合并列表且列表内数字从高到低_35个高级Python知识点总结

    No.1 一切皆对象 众所周知,Java中强调"一切皆对象",但是Python中的面向对象比Java更加彻底,因为Python中的类(class)也是对象,函数(function) ...

  9. python中标识符下划线用作开头_python python中那些双下划线开头的那些函数都是干啥用用的...

    1.写在前面 今天遇到了__slots__,,所以我就想了解下python中那些双下划线开头的那些函数都是干啥用用的,翻到了下面这篇博客,看着很全面,我只了解其中的一部分,还不敢乱下定义. 其实如果足 ...

最新文章

  1. pip安装mysql-python失败,并显示EnvironmentError:找不到mysql_config
  2. 知识点讲解二:关于requests里的timeout()
  3. 注意力机制在softmax时需要除以一个根号8的作用
  4. 设计模式之行为模式(1)-状态、策略、责任链、访问者
  5. 企业级 布署 vmvare Esxi 5.0.0 从零开始教程 (二) vSphere clinet 安装
  6. Vue使用Swiper看这一篇就够了
  7. 互联网产品经理的月薪是多少?治好奇!
  8. 电脑通过热点共享网络,手机连接热点可以访问其他内网
  9. 设置div的内容及子标签向右对齐
  10. 你的微信昵称,正在暴露你
  11. oracle连接超时是什么意思,oracle连接超时自动断开问题
  12. Linux使用445端口,利用enum4linux 445端口+wordpress插件任意文件上传的一次渗透
  13. 工厂的生产管理系统,即时掌握车间生产动态
  14. 小米2019秋招软件开发笔试题A选择部分解析
  15. 二分查找法及其四种变形(MATLAB)
  16. 几种常见的概率统计谬误
  17. 2021年北京积分落户名单公布了,爬了两个多小时得到了所有数据,有了惊人的发现(附源码)
  18. MATLAB LSB图像信息隐藏 最低位平面验证 以及PSNR SSIM评价
  19. ModuleNotFoundError: No module named ‘_bz2‘问题解决
  20. Java计算两年后的前一天yyyyMMdd

热门文章

  1. 借evdev之力 Linux全局热键魔改造
  2. Linux按文件内容查找文件
  3. Python遍历目录的4种方法
  4. Oracle 常用语句
  5. [转载]漫谈游戏中的阴影技术
  6. Basic:三层架构开发
  7. 【收藏】生产订单业务流程
  8. 财务思维01-财务报表
  9. 【PP操作手册】成品入库和订单报工
  10. 创建销售订单BAPI一些心得