一个对象能不能作为字典的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当做键试一下

1

2

3

4

5

6

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了

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

# 部分源码

 

class object:

    """ The most base type """

 

    def __hash__(self, *args, **kwargs):  # real signature unknown

        """ Return hash(self). """

        pass

 

 

class list(object):

    __hash__ = None

 

 

class set(object):

    __hash__ = None

 

 

class dict(object):

    __hash__ = None

那这样的话。。。我给他加一个hash不就能当字典的key了,key不就是可变的了。

注意

此处只是我跟着想法随便试,真的应用场景不要用可变类型作为字典的key。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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号元素的哈希值,那我直接用相同哈希值的对象是不是就能改变那本来不属于它的字典值呢?

1

2

3

4

5

6

7

8

9

10

11

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__方法试一下。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

class MyList(list):

    def __hash__(self):

        return hash(self[0])

 

    def __eq__(self, other):

        return self[0] == other

 

 

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}

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

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] == other

 

 

l1 = 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,找到相对应的那片内存空间,里面没有值的话就直接写入,对于字典来说就是新增键值对;如果里面已经有值了,那就判断新来的键和原来的那里的键是不是相等,相等就认为是一个键,对于字典来说就是更新值,不相等就再开空间,相当于字典新增键值对。

转自:https://www.weidianyuedu.com

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

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

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

  2. Python中字典的key都可以是什么?

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

  3. python字典相同key的值怎么分别取出_python字典值排序并取出前n个key值的方法

    python字典值排序并取出前n个key值的方法 今天在写一个算法的过程中,得到了一个类似下面的字典: {'user1':0.456,'user2':0.999,'user3':0.789,user: ...

  4. Python字典的key浅谈

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

  5. [Python] 字典 get(key, default=None):获取字典中相应键的对应值

    转自:Python 字典(Dictionary) get()方法 功能: get() 函数和setdefault()函数返回指定键的值,如果值不在字典中返回默认值. 语法: dict.get(key, ...

  6. python字典按照key排序_python中字典按key值排序的实现方法

    之前小编介绍了字典本身不可排序,但按值可以,小编也介绍了按value值排序的三种方法.sorted()函数可以对数字或字符串进行排序,按key排序只是输出的key值的排序列表,使用sorted()函数 ...

  7. [python] 字典 pop(key)函数:删除字典中key及其值,并返回该值

    功能 删除字典给定键 key 及对应的值,返回值为被删除的值.key 不在字典中,则返回 default 值. 一般会在更新字典的时候用到. 语法 value_deleted = dict_name. ...

  8. python字典--在key上使用正则表达式

    首先感谢 https://www.icode9.com/content-1-290270.html 最近在做爬虫的时候遇到一个问题: 抓取到的网页源码部分数据如下: <td width=&quo ...

  9. python case语句_高效使用Python字典,技巧都在这里!

    字典(dict)对象是 Python 最常用的数据结构 社区曾有人开玩笑地说:"Python企图用字典装载整个世界" 字典在Python中的重要性不言而喻,这里整理了几个关于高效使 ...

最新文章

  1. python调用数据库数据类型_ajax 读取python的数据库数据类型
  2. 粘包问题,以及在python中如何调用操作系统命令
  3. 网易智慧企业春招开幕:同心战疫,共盼花开
  4. Apache安装及jboss部署说明文档1
  5. 面向 Android 软件开发套件(SDK)的 x86 Android* 系统映像许可协议
  6. ipad连接电脑显示不在充电_笔记本电脑和投影仪连接后为什么投影仪不能显示电脑内容?...
  7. Configure your new Fedora
  8. 计算机组装与维护评课稿,计算机病毒评课稿
  9. Twaver-HTML5基础学习(12)连线(Link)
  10. werfault.exe出现的原因与解决办法以及werfault.exe 该内存不能为written如何解决?
  11. IC验证笔试题(平头哥)
  12. C++面向对象(三):类和对象
  13. linux驱动面试题目汇总
  14. 【论文泛读85】基于上下文的句子相似度
  15. excel去除重复项
  16. chirp和tone burst信号激励
  17. 《ANSYS CFX 14.0超级学习手册》——1.4 CFD软件结构及常用的CFD软件
  18. python并行运算 Parallel
  19. poj1742 - Coins
  20. doe报告模板_波峰焊DOE实验报告范本(EXCEL档) .xls

热门文章

  1. 解决海信智能电视不能安装U盘上的安装包的问题
  2. 途胜怎样与android手机互联,汽车知识普及:现代途胜车载蓝牙怎么连接 途胜手机互联映射教程...
  3. CAD高程点转入ArcGIS
  4. Android逆向之旅--龙之契约游戏钻石内购破解分析
  5. Self-supervised Equivariant Attention Mechanism for Weakly Supervised Semantic Segmentation
  6. 公众号接入通联支付大致流程
  7. 修改C:\Users 下面文件夹的名称
  8. 记一次测试环境的灾难修复(排错及思路)-Docker Overlay2的出错;
  9. 中国增生性糖尿病性视网膜病的治疗方法市场趋势报告、技术动态创新及市场预测
  10. MATLAB矩阵生成函数和基本运算