你有一個誤解,hash算法針對的是元素的內容,并不是針對指針,所以指針不變不等于可hash。
如果你想深究細節的話,可以看tuple的源碼:
static Py_hash_t
tuplehash(PyTupleObject *v)
{
Py_uhash_t x; /* Unsigned for defined overflow behavior. */
Py_hash_t y;
Py_ssize_t len = Py_SIZE(v);
PyObject **p;
Py_uhash_t mult = _PyHASH_MULTIPLIER;
x = 0x345678UL;
p = v->ob_item;
while (--len >= 0) {
y = PyObject_Hash(*p++);
if (y == -1)
return -1;
x = (x ^ y) * mult;
/* the cast might truncate len; that doesn't change hash stability */
mult += (Py_hash_t)(82520UL + len + len);
}
x += 97531UL;
if (x == (Py_uhash_t)-1)
x = -2;
return x;
}
注意這里有一個循環,tuple會對其中每個元素調用PyObject_Hash,將結果進行異或運算再加上一個常量作為整個tuple的hash。
如果tuple中有一個元素是list,那么PyObject_Hash將調用list的hash算法,然而list定義就表明它根本不實現hash:
PyTypeObject PyList_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"list",
sizeof(PyListObject),
0,
(destructor)list_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
(reprfunc)list_repr, /* tp_repr */
0, /* tp_as_number */
&list_as_sequence, /* tp_as_sequence */
&list_as_mapping, /* tp_as_mapping */
PyObject_HashNotImplemented, /* tp_hash */
...
再看 PyObject_HashNotImplemented 的實現:
Py_hash_t
PyObject_HashNotImplemented(PyObject *v)
{
PyErr_Format(PyExc_TypeError, "unhashable type: '%.200s'",
Py_TYPE(v)->tp_name);
return -1;
}
這個信息很眼熟吧?
結論就是,只要tuple中有一個元素是不可hash的(不限于list),那么整個tuple都是不可hash的。