python的可哈希和不可哈希
哈希函数
先来看一下官方文档上面对hashable的说明:
如果一个对象在其生命周期内有一个固定不变的哈希值 (这需要__hash__()方法) 且可以与其他对象进行比较操作 (这需要__eq__()方法) ,那么这个对象就是可哈希对象 (hashable) 。可哈希对象必须有相同的哈希值才算作相等。
由于字典 (dict) 的键 (key) 和集合 (set) 内部使用到了哈希值,所以只有可哈希 (hashable) 对象才能被用作字典的键和集合的元素。
所有python内置的不可变对象都是可哈希的,同时,可变容器 (比如:列表 (list) 或者字典 (dict) ) 都是不可哈希的。用户自定义的类的实例默认情况下都是可哈希的;它们跟其它对象都不相等 (除了它们自己) ,它们的哈希值来自id()方法。
字典的键
字典的键和集合都只能存放可哈希对象,当我们用不可哈希对象如list运行时会报错如下
TypeError: unhashable type: ‘list’
字典是根据键的哈希值查找对应值的,通过以下代码,可以看到元组是根据内容而不是id产生哈希值的
>>> a = (1,2)
... b = tuple([1,2])
... print(id(a))
... print(id(b))
... print(b)
... c = {a:1}
... print(c[b])
2477604860032
2477611649792
(1, 2)
集合的对象
当使用set()函数将不可哈希对象转换为集合时,同样会报错,如下
>>> a = [1,[2]]
... b = set(a)
... print(b)
Traceback (most recent call last):
File "<input>", line 2, in <module>
TypeError: unhashable type: 'list'
自定义对象的哈希值
自定义对象默认是可哈希的,且根据对象的id产生哈希值,如下
>>> class Dog(object):
... def __init__(self,name):
... self.name = name
... dog1 = Dog("agou")
... print(dog1)
... dog2 = Dog("agou")
... print(dog2)
... print(Dog("agou"))
... a = {dog1:2}
... print(a[dog1])
... print(a[dog2])
<__main__.Dog object at 0x00000240DD18D610>
<__main__.Dog object at 0x00000240DD2C5160>
<__main__.Dog object at 0x00000240DD18DFA0>
2
Traceback (most recent call last):
File "<input>", line 11, in <module>
KeyError: <__main__.Dog object at 0x00000240DD2C5160>
整型、浮点型、字符串的哈希值
对整型、浮点型、字符串分别求哈希值,结果如下
>>> print(hash(1));print(hash(0.5));print(hash('xyz'))
1
1152921504606846976
7472338868594177729
>>> print(hash(1));print(hash(0.5));print(hash('xyz'))
1
1152921504606846976
7472338868594177729
print(hash(1));print(hash(0.5));print(hash('xyz')) # pycharm下
1
1152921504606846976
6139473104200715737
可以看出整型的哈希值是固定的,浮点型的哈希值是一串整数且不见变化,字符串的哈希值是一串整数且在pycharm下每次运行会变化。
Python中可哈希和不可变
python中的不可变(immutable)对象都是可哈希(hashable)对象,用户自定义实例对象也默认可哈希,用户自定义实例对象的哈希值根据其id产生,故可变对象也可能可哈希。