关于python中元组、字典的可变性。
对可变对象的疑虑点,请各位大佬指点迷津,多谢!
问题描述:
- 元组
tuple
的元素只能容纳不可变对象,且其中的元素可以是列表list
,因为实际存放的是列表(可变对象)的地址,只要这个可变列表的地址不变,就算列表中的元素变化了,也不能说是元组元素的变动。 - 字典
dict
的key不能是可变元素,因为需要用key去hash取值。如果此时key为列表(可变对象),则字典会报错:TypeError: unhashable type: 'list'
。
那么问题来了:
同样是可变元素list
,为什么在元组tuple
里面作为元素值是合法的、是取地址
的、是不可变的,但是在字典dict
里面作为key的值就是非法的、是取值
的、是可变的。
这样的设计,感觉不符合使用上的一致性或直观的理解性吧,因为规则不一致。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
你想当然地对“不可变序列”这个词语产生了误解。
首先我们要理解,何为“不可变对象”。
然后我们思考下,序列的value是什么东西。
能否hash根据这些元素的散列函数计算的,而不是内容(值)。
在Python的文档词汇表中查看此段落。
某些东西是否可以散列,以及它是如何散列的,取决于其
.__hash__()
方法的实现。Python本身并不知道对象的可变性。具体而言,
tuple
恰好基于其元素散列自身,而list
根本没有散列函数 -.__hash__()
方法没有被实现(并且有充分的理由)。这就是为什么如果tuple
里包含有list
类型的元素, 则tuple
是不能哈希的。Python 文档:
这也是为什么你不必为你的类定义
.__hash__()
- 在这种情况下Python自动为你定义。但默认实现并不会将实例字段值考虑进去。这就是为什么您可以更改对象内部的值而不更改其哈希值的原因。自定义类的哈希函数的默认(CPython)实现依赖于一个对象 id(),而不依赖于它内部的值。它是一个实现细节,但它在Python版本之间有所不同。在Python的更新版本中,hash()和id()之间的关系涉及一些随机化。
但是它实际上如何散列呢?
虽然细节非常复杂并且可能涉及一些高级数学,但是元组对象的散列函数的实现是用C语言编写的,可以在这里看到(参见
static Py_hash_t tuplehash(PyTupleObject *v)
。计算涉及使用每个元组元素的哈希对一个常量进行异或运算。负责元素散列的行是这样的:
所以对特定的数据结构来说,有一大波
XOR
操作加在数据结构的每个元素的来进行哈希。是否使用这些元素的内容取决于它们的特定散列函数。编译自:
https://stackoverflow.com/que...
dict 的 key 必须要是能够 hash 的
元组是一组值的序列。 其中的值可以是任意类型, 使用整数索引,