答:一个对象能不能作为字典的key,就取决于其有没有__hash__方法。所以所有python自带类型中,除了list、dict、set和内部至少带有上述三种类型之一的tuple之外,其余的对象都能当key。

比如数值/字符串/完全不可变的元祖/函数(内建或自定义)/类(内建或自定义)/方法/包等等你能拿出手的,不过有的实际意义不高。还有数值型要注意,因为两个不同的相等数字可以有相同的哈希值,比如1和1.0。

解释:

代码版本:3.6.3;文档版本:3.6.6

Unlike sequences, which are indexed by a range of numbers, dictionaries are indexed by keys, which can be any immutable type; strings and numbers can always be keys. Tuples can be used as keys if they contain only strings, numbers, or tuples; if a tuple contains any mutable object either directly or indirectly, it cannot be used as a key. You can’t use lists as keys, since lists can be modified in place using index assignments, slice assignments, or methods like append()and extend().

  • 字典的键可以是任意不可变类型,需要注意的是tuple元组作为键时,其中不能以任何方式包含可变对象。

那。。到底什么样的是不可变类型呢?不可能给对象专门标注一个属性是可变类型还是不可变类型啊,这没有任何其他意义,一定是通过其他途径实现的。把list当做键试一下

a = [1, 2, 3]
d = {a: a}# 第二行报错:
# TypeError: unhashable type: 'list'

报错说list类型是不可哈希的,噢,原来是靠能不能hash来判断的,另外文档下面接着说同一字典中每个键都是唯一的,正好每个对象的哈希值也是唯一的,对应的很好。

It is best to think of a dictionary as an unordered set of key: value pairs, with the requirement that the keys are unique (within one dictionary).

查看源代码可以看到object对象是定义了__hash__方法的,

而list、set和dict都把__hash__赋值为None了

# 部分源码class object:""" The most base type """def __hash__(self, *args, **kwargs):  # real signature unknown""" Return hash(self). """passclass list(object):__hash__ = Noneclass set(object):__hash__ = Noneclass dict(object):__hash__ = None

那这样的话。。。我给他加一个hash不就能当字典的key了,key不就是可变的了。注意:此处只是我跟着想法随便试,真的应用场景不要用可变类型作为字典的key。

class MyList(list):"""比普通的list多一个__hash__方法"""def __hash__(self):# 不能返回hash(self)# hash(self)会调用self的本方法,再调用回去,那就没完了(RecursionError)# 用的时候要注意实例中至少有一个元素,不然0怎么取(IndexError)return hash(self[0])l1 = MyList([1, 2])  # print(l1) -> [1, 2]
d = {l1: 'Can?'}
print(d)  # -->  {[1, 2]: 'Can?'}
l1.append(3)
print(d)  # {[1, 2, 3]: 'Can?'}
print(d[l1])  # -->  Can?

到这里就可以肯定的说,一个对象能不能作为字典的key,就取决于其有没有__hash__方法。所以所有python自带类型中,目前我已知的除了list、dict、set和内部带有以上三种类型的tuple之外,其余的对象都能当key。而我们自己定义的类,一般情况下都直接间接的和object有关,都带有__hash__方法。

另外我想到,既然字典的键是唯一的,而哈希值也是唯一的,这么巧,键的唯一性不会就是用哈希值来确定的吧?我上一个例子中__hash__方法返回的是0号元素的哈希值,那我直接用相同哈希值的对象是不是就能改变那本来不属于它的字典值呢?

class MyList(list):def __hash__(self):return hash(self[0])l1 = MyList([1, 2])  # print(l1) -> [1, 2]
d = {}
d[l1] = l1
print(d)  # {[1, 2]: [1, 2]}
d[1] = 1
print(d)  # {[1, 2]: [1, 2], 1: 1}

竟然没有改成功而是新添加了一个键值对,可self[0]就是1啊,哈希值一样啊,怎么会不一样呢?难道要键的值一样才能判断是同一个键吗?重写__eq__方法试一下。

class MyList(list):def __hash__(self):return hash(self[0])def __eq__(self, other):return self[0] == otherl1 = MyList([1, 2])  # print(l1) -> [1, 2]
d = {}
d[l1] = l1
print(d)  # {[1, 2]: [1, 2]}
d[1] = 1
print(d)  # {[1, 2]: 1}

这回成功了,那就是__hash__返回值相等,且eq判断也相等,才会被认为是同一个键。那这两个先判断哪个呢?加个代码试一下

class MyList(list):def __hash__(self):print('hash is run')return hash(self[0])def __eq__(self, other):print('eq is run')return self[0] == otherl1 = MyList([1, 2])  # print(l1) -> [1, 2]
d = {}
d[1] = 1
d[l1] = 'l1'
print(d)# 结果:
# hash is run
# eq is run
# {1: 'l1'}

__hash__先执行,另外字典在内存中存储数据的位置和键的hash也是有关的,逻辑上也像印证。先计算hash,找到相对应的那片内存空间,里面没有值的话就直接写入,对于字典来说就是新增键值对;如果里面已经有值了,那就判断新来的键和原来的那里的键是不是相等,相等就认为是一个键,对于字典来说就是更新值,不相等就再开空间,相当于字典新增键值对。

在你验证自己想法的时候可能遇到__hash__和__eq__的一些想不到的麻烦,可以看这里:__hash__和__eq__的继承使用问题

Python中字典的key都可以是什么?相关推荐

  1. python中可以作为定界符_在 Python 中,字典和集合都是用一对 作为定界符,字典的每个元素有两部分组成,即 和 ,其中 不允许重复。_学小易找答案...

    [多选题]路由器A的G0/0/1接口配置信息如下,下列说法正确的有?(多选) acl number 3000 rule 5 deny 17 rule 10 deny 89 rule 15 deny 6 ...

  2. python中key什么意思_Python中字典的key都可以是什么

    作者:Inotime 来源:CSDN 原文:https://blog.csdn.net/lnotime/article/details/81192207 答:一个对象能不能作为字典的key,就取决于其 ...

  3. 在python中字典和集合都是用一对什么作为界定符_Python习题(一)

    1. 实现1-100的所有的和print('**********方法一:for循环**********') s1=0 for a in range(1,101): s1+=a print s1, pr ...

  4. python中字典按键或键值排序

    字典排序 在程序中使用字典进行数据信息统计时,由于字典是无序的所以打印字典时内容也是无序的.因此,为了使统计得到的结果更方便查看需要进行排序.Python中字典的排序分为按"键"排 ...

  5. python中字典和集合的区别_Python中字典和集合学习小结

    映射类型: 表示一个任意对象的集合,且可以通过另一个几乎是任意键值的集合进行索引 与序列不同,映射是无序的,通过键进行索引 任何不可变对象都可用作字典的键,如字符串.数字.元组等 包含可变对象的列表. ...

  6. python英语字典程序修改_详解如何修改python中字典的键和值

    我们知道python中字典是无序的,它们都是通过hash去对应的.一般的如果我们需要修改字典的值,只需要直接覆盖即可,而修改字典的键,则需要使用字典自带的pop函数,示例如下: t = {} t['a ...

  7. json和python中字典的区别和联系_Python 中json与字典的关系

    Python开发中字典和 json的概念区别: json.dumps( dict ) 字典变为字符 json.loads( jsoninput ) 字符变为字典 一.字典 字典是一种数据结构,而jso ...

  8. 【Python】Python实战从入门到精通之四 -- 教你使用Python中字典

    本文是Python实战–从入门到精通系列的第四篇文章: Python实战从入门到精通第一讲–Python中的变量和数据类型 Python实战从入门到精通第二讲–Python中列表操作详解 Python ...

  9. python中字典使用_python中字典的使用

    python中的字典的特性: 在字典中的元素是散列存放的,没有顺序, 在进行增删改查的时候使用字典中需要的关键字(key)即可. 一: 创建字典 1)直接定义一个: dict = {'ob1':'co ...

最新文章

  1. python 数据处理 书_Python数据处理
  2. Apache将整合Google Wave功能
  3. 给你安利几个牛逼的公众号~
  4. CodeForces - 1529F It‘s a bird! No, it‘s a plane! No, it‘s AaParsa!(最短路+思维建图)
  5. 何亚明:Facebook的工具文化和多媒体QoE
  6. python根据2点经纬度计算距离
  7. C++ 学习之旅(14)——构造函数constructors和析构函数destructors
  8. Jenkins自动化部署容器
  9. WPF 绕圈进度条(一)
  10. 【英语学习】【English L06】U01 Breakfast L6 Make at home vs. eat out
  11. 剑指Offer之寻找链表中环的入口问题
  12. 《腾讯是怎么长大的》读书笔记
  13. VoLTE业务端到端流程
  14. 微型计算机硬件系统基本组成是什么,计算机硬件系统基本组成有什么?
  15. 中国白领最苦累的六大城市
  16. javascript html 去除,javascript去除html标签
  17. 支付宝免费领取7天优酷黄金会员 1.88元购买1个月优酷黄金会员
  18. Spring Bean 配置相关的注意事项
  19. 如何在ASP.Net Core中使用辅助服务
  20. 红黑树和红黑树的原理详解

热门文章

  1. python初学总结八数码小游戏
  2. IOS的 testflight测试设置(内部测试)
  3. Dva.js+umi入门案例(models层,services层,components层详细代码与解析)
  4. 网络直播系统的架构,基础版直播间搭建 1
  5. 快速学习-获取 Rinkeby 测试以太
  6. 2018下半年教资信息技术学科知识与教育能力——主观题
  7. 从 Linux 安全看,eBPF 的出现是“天使”还是“恶魔”?
  8. 记录:springboot@ConfigurationProperties来获取配置文件中的属性配置
  9. php泥浆是什么,深厚砂性土层钻孔桩中PHP泥浆应用
  10. python实现数学函数图像