Discuss / Python / 对可变对象的疑虑点,请廖大佬指点迷津,多谢!

对可变对象的疑虑点,请廖大佬指点迷津,多谢!

Topic source

LHYNGU

#1 Created at ... [Delete] [Delete and Lock User]

对可变对象的疑虑点,请廖大佬指点迷津,多谢!

问题描述:

  1. 元组tuple的元素只能容纳不可变对象,且其中的元素可以是列表list,因为实际存放的是列表(可变对象)的地址,只要这个可变列表的地址不变,就算列表中的元素变化了,也不能说是元组元素的变动。

  2. 字典dict的key不能是可变元素,因为需要用key去hash取值。如果此时key为列表(可变对象),则字典会报错:TypeError: unhashable type: 'list'

那么问题来了: 同样是可变元素list,为什么在元组tuple里面作为元素值是合法的、是取地址的、是不可变的,但是在字典dict里面作为key的值就是非法的、是取的、是可变的。

这样的设计,感觉不符合使用上的一致性或直观的理解性吧,因为规则不一致。

因为 dict中的key必须是可hash的,list是不可hash的,所以不合法

廖雪峰

#3 Created at ... [Delete] [Delete and Lock User]

dict拒绝list作为key不是因为list是可变,而是dict要求任何key对象都必须实现__hash__

实现了__hash__即使是可变的也可以作为dict的key,但是一个对象的__hash__必须始终保证返回的值不能变,如果变了,就会导致dict工作不正常。

LHYNGU

#4 Created at ... [Delete] [Delete and Lock User]

懂了懂了,多谢廖大佬。^_^

也就是说,

  • list里面的值其实只要满足不可变的特性就行了。
  • dictkey的要求是可__hash__,而且同一个key__hash__的结果必须相同,那么是不是key在极端情况下写一个可变对象也行,只要这个对象的__hash__每次都能给一个不变的固定值就可以了。

还有,

  • tuple里面用的是相关对象的地址,这是语言设计本身的特性,就是这样设计的,哪怕里面是简单的字符a,那也是用的a地址
  • dictkey用的是真真切切的对象的值,而不是对象的地址,且要求此对象值可__hash____hash__值不可变。

廖大佬,以上是我的理解,不正确还望不吝斧正,多谢了!

廖雪峰

#5 Created at ... [Delete] [Delete and Lock User]

dict的原理你看JDK的HashMap就明白了

根据key查找的逻辑:

给出一个key,先计算hashCode(),这样可以直接定位到0个(没找到)、1个或多个(hash碰撞)value,然后,根据equals()依次比较key,返回对应的value

dict的原理决定了作为key的对象hash不能变,不然用"abc"放进去的value再用"abc"就查不出来了。两个不同的对象,如果逻辑上相等,必须hash相等,因为你用来查找的key不一定就是你放进去的key:

originalKey = Student('Bob')
aDict[originalKey] = 'ok'

anotherKey = Student('Bob') # 新对象
value = aDict[anotherKey] # 'ok'

LHYNGU

#6 Created at ... [Delete] [Delete and Lock User]

好的,廖大佬,看来我革命还得继续,我还得努力,不知道的地方太多了。 再次感谢廖大佬不厌其烦的讲解,赞。


  • 1

Reply