python-对象之hashable&unhashable与immutable&mutable

首先,hashable和unhashable

先来看一下官方文档上面对hashable的解释:
hashable
An object is hashable if it has a hash value which never changes during its lifetime (it needs a __hash__() method), and can be compared to other objects (it needs an __eq__() method). Hashable objects which compare equal must have the same hash value.
Hashability makes an object usable as a dictionary key and a set member, because these data structures use the hash value internally.

如果一个对象在其生命周期内有一个固定不变的哈希值 (这需要__hash__()方法) 且可以与其他对象进行比较操作 (这需要__eq__()方法) ,那么这个对象就是可哈希对象 (hashable) 。可哈希对象必须有相同的哈希值才算作相等。
由于字典 (dict) 的键 (key) 和集合 (set) 内部使用到了哈希值,所以只有可哈希 (hashable) 对象才能被用作字典的键和集合的元素。
所有python内置的不可变对象都是可哈希的,同时,可变容器 (比如:列表 (list) 或者字典 (dict) ) 都是不可哈希的。用户自定义的类的实例默认情况下都是可哈希的;它们跟其它对象都不相等 (除了它们自己) ,它们的哈希值来自id()方法。

python内置的可哈希对象可以使用hash()或者__hash__()方法来查看它的哈希值,比如a.__hash__()或者hash(a),或者如下:

>>> a = 1
>>> a.__hash__()
1
>>> b = 1
>>> b.__hash__()
1
>>> id(a)
1571750352
>>> id(b)
1571750352
# 可以看到这里两个对象(a和b)的哈希值和id值都相同

>>> c = 1.2
>>> c.__hash__()
461168601842738689
>>> d = 1.2
>>> d.__hash__()
461168601842738689
>>> id(c)
1688105757288
>>> id(d)
1688105757072
# 这里两个对象(c和d)的哈希值相同,id值却不同了
# 说明一下:为什么a和b的哈希值和id都一样,而c和d的哈希值相同id却不同呢?解释器在对值很小的int和很短的字符串的时候做了一点小优化,只分配了一个对象,所以前面a和b的id一样了,这里c和d不符合优化条件,就给它们分别分配了两个对象,id值就不一样了。

>>> class A:
...     pass
...     
>>> cls_a = A()
>>> cls_b = A()
>>> cls_a
0x000001890DB69898>
>>> cls_b
0x000001890DB6EDD8>
>>> cls_a.__hash__()
-9223371931345262199
>>> cls_b.__hash__()
-9223371931345260835
>>> id(cls_a)
1688152217752
>>> id(cls_b)
1688152239576
# 这里两个对象(cls_a和cls_b)哈希值和id都不一样
# 说明一下:由于用户自定义的类的实例其哈希值与id有关,所以id值和哈希值都不相同,就如官方文档里说的,实例只跟自己相等。

接下来看mutable和immutable

python里面,传递的都是对象的引用,也可以理解为传递的是地址。基于这一点来理解可变和不可变。
可变也叫做原地可变,我理解的意思是:所谓原地是说不需要新开辟一个内存单元,那么原地可变就是操作都是在原内存单元进行的。原地可变的数据类型有:list、dict、set,看原地可变的例子:

>>> list_a = [1, 2, 3]
>>> list_a
[1, 2, 3]
>>> id(list_a)
1688152366472
>>> list_a.append(4)
>>> list_a
[1, 2, 3, 4]
>>> id(list_a)
1688152366472
>>> list_a[0] = 0
>>> list_a
[0, 2, 3, 4]
>>> id(list_a)
1688152366472
# 这里可以看到list_a的内容改变了,但是其id没有变,在原内存单元上进行增加修改操作,list_a并没有申请另外的内存单元

不可变也叫原地不可变,原地的理解同上,原地不可变就是说这个对象一旦改变就需要新的内存单元。原地不可变的数据类型有:int、float、complex、string、tuple,看例子:

>>> a = 1
>>> a
1
>>> id(a)
1571750352
>>> a = 2
>>> a
2
>>> id(a)
1571750384
# 这里可以看到,a的值一旦改变id就会跟着改变,即原地不可变

只有原地可变对象有add(),append()等操作。

hashable和immutable的关系

The two ideas are related because objects which are used as hash keys must typically be immutable so their hash value doesn’t change. If it was allowed to change then the location of that object in a data structure such as a hashtable would change and then the whole purpose of hashing for efficiency is defeated.

由于hash key必须是不可变的,对应的hash value才能是不变,所以不可变和可哈希是有关系的。如果hash key允许改变,那么像hashtable这样数据结构的对象将会改变,整个hash映射就都会失效。
关系描述引自[stackoverflow]

你可能感兴趣的:(python)