python基础问题请教一下,dict的key可以是([1, 2],)这种类型的吗?
众所周知,python的dict对象,是一个不可哈希对象,是可变的。他的key只接受 哈希类型 的数据,也就是 字符串、整型、浮点型、布尔、元组和None
;而不可hash的有 字典、数组、集合
是不能作为key的。
遇到一个疑问,没找到合理的解释,求释疑。
In [133]: a = {}In [134]: a[(1, 2)] = 'abc'
In [135]: a
Out[135]: {(1, 2): 'abc'}
################
In [136]: a[([1, 2],)] = 'def'
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In [136], line 1
----> 1 a[([1, 2],)] = 'def'
TypeError: unhashable type: 'list'
这里面报错的部分是字典的key出现了不可哈希对象,list
。
但是我用 ([1, 2],)
包裹了,这个整体应当是一个哈希对象才对,而且是 tuple
不是 list
。应当符合字典key的数据要求类型啊。
python">In [138]: from typing import HashableIn [139]: isinstance(([1, 2],), Hashable)
Out[139]: True
通过校验结果,可以看到 ([1, 2],)
确实是可哈希的。但上面那个报错我就不太理解,希望有大佬能提点一下,没找到官方解释。
另外,补充一个例子:
In [141]: class example(object): ...: def __init__(self, a):
...: self.value = a
...: def __eq__(self, rhs):
...: return self.value == rhs.value
...: def __hash__(self):
...: return hash(self.value)
...:
In [150]: a = example(2)
...: d = {a: "first"}
...: a.data = 2
...: d[a] = 'second'
In [151]: d
Out[151]: {<__main__.example at 0x10a5d3d30>: 'second'}
In [153]: isinstance(a, Hashable)
Out[153]: True
官方文档,看到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.
Most of Python’s immutable built-in objects are hashable; mutable containers (such as lists or dictionaries) are not; immutable containers (such as tuples and frozensets) are only hashable if their elements are hashable.
Objects which are instances of user-defined classes are hashable by default. They all compare unequal (except with themselves), and their hash value is derived from their id().
回答:
hashable
: 对象的__hash__()
函数。
看下tuple
的__hash__()
函数实现。
https://github.com/python/cpy...
static Py_hash_ttuplehash(PyTupleObject *v)
{
Py_ssize_t i, len = Py_SIZE(v);
PyObject **item = v->ob_item;
Py_uhash_t acc = _PyHASH_XXPRIME_5;
for (i = 0; i < len; i++) {
Py_uhash_t lane = PyObject_Hash(item[i]);
if (lane == (Py_uhash_t)-1) {
return -1;
}
acc += lane * _PyHASH_XXPRIME_2;
acc = _PyHASH_XXROTATE(acc);
acc *= _PyHASH_XXPRIME_1;
}
/* Add input length, mangled to keep the historical value of hash(()). */
acc += len ^ (_PyHASH_XXPRIME_5 ^ 3527539UL);
if (acc == (Py_uhash_t)-1) {
return 1546275796;
}
return acc;
}
会计算所有元素的哈希值。
其实就是tuple
的hash值,是根据其里面所有元素的hash值确定的。如:
t1 = (1, 2, 3)t1_hash = t1.__hash__()
# t1.__hash__() 这个值的计算
# 类似这种计算
def tuple_hash(t1):
t_hash = 0
for i in t1:
i_hash = i.__hash__()
# 为了避免哈希碰撞,做了一系列处理
t_hash += magic_func(i_hash)
return t_hash
以上是 python基础问题请教一下,dict的key可以是([1, 2],)这种类型的吗? 的全部内容, 来源链接: utcz.com/p/938682.html