作者:Inotime

来源:CSDN

原文:https://blog.csdn.net/lnotime/article/details/81192207

答:一个对象能不能作为字典的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). """

pass

class list(object):

__hash__ = None

class set(object):

__hash__ = None

class 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] == 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判断也相等,才会被认为是同一个键。那这两个先判断哪个呢?加代码试一下

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

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

---------------------

python中key什么意思_Python中字典的key都可以是什么相关推荐

  1. python把字符串放到列表_python中for循环把字符串或者字典添加到列表的方法

    python中如何for循环把字符串添加到列表? 实例: 1.单个字符串用for循环添加到列表中: # 把L1中的字符串添加到列表alist里面 L1 = 'MJlifeBlog' alist = [ ...

  2. python 获取 字典中的指定键_python中字典方法的详细教程

    上篇文章讲到了python字典的基础知识,今天继续python中哈希(字典的应用)方法的应用. 前章回顾: python字典的应用及案例分析 字典方法: dict.clear() 删出字典内所有的元素 ...

  3. python列表怎么写文件_python中以字典为元素的列表怎么写入文本文件

    python如何将列表中的元素添加进字典纵然被命运的铁蹄狠狠践踏,也顽强地长出自己的根芽. 录入自己和另一个人的名字的汉语拼音简写,然后依据标识符中字母的数值两个人,一颗心,依偎的不是爱情而是那小温暖 ...

  4. python里的join方法_python中join()方法介绍

    描述 Python join() 方法用于将序列中的元素以指定的字符连接生成一个新的字符串. 语法 join()方法语法: str . join ( sequence ) 参数 sequence -- ...

  5. python中扑克牌类设计_Python中的计数 Counter类

    点击上方"AI机器学习与深度学习算法",选择"星标"公众号 原创干货,第一时间送达 在很多场景中经常会用到统计计数的需求,比如在实现 kNN 算法时统计 k 个 ...

  6. python将列表中反序输出_python中sorted怎么反序排列

    2017-10-30 回答 [python] sorted函数 我们需要对list.dict进行排序,python提供了两个方法 对给定的list l进行排序, 方法1.用list的成员函数sort进 ...

  7. python中的参数函数_python中函数与参数的简介

    函数 函数就是具有某个具体功能的工具 而使用用函数能提供开发效率,减少代码冗余,提高程序的扩展性. 在Python中,函数有五大要点:分别是def.函数名.函数体.参数.返回值,以及两个英文版符号,分 ...

  8. python中的json函数_python中装饰器、内置函数、json的详解

    装饰器 装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象. 先看简单例子: def run(): time.sleep(1 ...

  9. python sort函数返回值_python中 sort方法 和sorted函数

    sort和sorted在python中常用语列表(或类列表)的排序,但是在python中有所区别. 他们的唯一的共同点恐怕就是都可以对列表排序,区别: 1. sorted是python的内置函数,可以 ...

最新文章

  1. 乌班图好玩的命令_乌班图必须知道的60个命令
  2. VS2013配置编译Caffe-Win10_X64
  3. C++ 11右值引用
  4. springboot+jsp+mybatis项目实例(后台成功,但是无法跳转jsp页面,没有实体类的注解,看springboot+jsp第二弹相关配置,即可成功配置jsp)...
  5. 回家了,写博文继续!
  6. Python文件读写——使用“with open ... as f”进行文件打开的操作
  7. APMCM亚太地区数学建模历年赛题
  8. 为什么在项目中要慎用RxBus
  9. 逻辑结构定义及其分类
  10. 任天堂游戏 html5,任天堂Switch游戏销量排行Top40,赶快收藏跟着买就对啦!
  11. SQL特殊comment语法
  12. iOS端如何实现带UI截屏分享
  13. 谷歌浏览器怎样把网页全部内容保存为.mhtml文件?
  14. Node.js 运行.js文件出现错误找不到文件的解决办法
  15. C#Office.Interop.Excel.dll读写表格
  16. 如何使用Aplayer播放器
  17. 最好的C#教程和参考书
  18. 支持python的量化交易平台
  19. 七日杀修改服务器名称,七日杀怎么改名字_联机改名字方法_快吧单机游戏
  20. [python3.6] 图片排列与展示

热门文章

  1. 《牛津字典精华总结》- 初阶系列 - 字母 - A
  2. MySQL 服务器是什么_什么是 MySQL?
  3. 使用fastjson解析json抓取新浪新闻文章
  4. 在win10更新的时候出现0x80240004错误代码怎么解决。
  5. 使用LamdbaUpdateWrapper的setSql作用及风险
  6. 互联网、因特网及万维网之间的区别与联系
  7. 计算机上如何保存ico格式,PS怎么保存ico格式
  8. ExtJS教程(5)---Ext.data.Model之高级应用
  9. 牧师与魔鬼 -- version2 动作分离
  10. HTTP/HTTPS与流量劫持/DNS劫持