类型错误:不可哈希的类型。

61
我正在尝试获取一个元组的列表:类似于 [ [(1,0),(2,0),(3,0)],[(1,1),(2,1),(3,1)....]]。我使用了以下语句

set([(a,b)for a in range(3)]for b in range(3))

但它给了我一个错误

TypeError: unhashable type: 'list'

我有两个问题要问Python专家:

a) 当我查看Python中Hashable的定义时 -

"如果一个对象具有在其生命周期内永远不会更改的哈希值,则它是可哈希的(需要一个hash()方法)"

当我对上述表达式使用dir函数时,

dir([(a,b)for a in range(3)]for b in range(3))

看起来代码中已经定义了__hash__,那么我为什么会得到错误?

我通过使用list命令获得了[[(0, 0), (1, 0), (2, 0)], [(0, 1), (1, 1), (2, 1)], [(0, 2), (1, 2), (2, 2)]]

list(list((a,b) for a in range(3)) for bin range(3))
b) 列表和集合都接受Iterable作为参数。一个可以工作(列表),而另一个不行(集合),为什么?
6个回答

38
你正在通过set(...)调用创建一个set,而set需要可哈希的项。你不能有一个列表的集合,因为列表是不可哈希的。 [[(a,b) for a in range(3)] for b in range(3)]是一个列表。它不是一个可哈希的类型。你在dir(...)中看到的__hash__不是一个方法,只是None。
列表推导返回一个列表,你不需要在那里显式地使用list,只需使用:
>>> [[(a,b) for a in range(3)] for b in range(3)]
[[(0, 0), (1, 0), (2, 0)], [(0, 1), (1, 1), (2, 1)], [(0, 2), (1, 2), (2, 2)]]

试试这些:
>>> a = {1, 2, 3}
>>> b= [1, 2, 3]
>>> type(a)
<class 'set'>
>>> type(b)
<class 'list'>
>>> {1, 2, []}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> print([].__hash__)
None
>>> [[],[],[]] #list of lists
[[], [], []]
>>> {[], [], []} #set of lists
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

2
那么哪些类型是不可哈希的? - x-yuri

23

简述:

- 无法将列表、集合或字典哈希后放入集合中

- 可以将元组哈希后放入集合中。

示例:

>>> {1, 2, [3, 4]}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

>>> {1, 2, (3, 4)}
set([1, 2, (3, 4)])
请注意,哈希有一定的递归性质,上述内容也适用于嵌套项。
>>> {1, 2, 3, (4, [2, 3])}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

字典的键也是可哈希的,因此上述内容也适用于字典的键。


我正在处理列表的列表,所以这非常有用。谢谢。 - NWMT
创建一个列表的元组表示,比通过例如 repr([1,2,3]) 创建字符串表示更快,对吗?那么嵌套列表呢? - Nil
1
对于嵌套列表,您可以使用推导式,例如,对于一个二维列表 a = [[1,2],[3,4]] # a 2 by 2 matrix 可以通过 a = set(tuple(tuple(x) for x in a))) 进行转换。 - AlexeyGy

14
  • 列表是不可哈希的,因为其内容可以在其生命周期内发生更改。您可以随时更新列表中包含的项。

  • 列表不使用哈希进行索引,因此它不受哈希项目的限制。


9

真正的原因是因为set使用哈希函数来区分不同的值。这意味着集合只允许可哈希对象。为什么列表不可哈希已经指出。


7

...所以你应该做类似于这样的事情:

set(tuple ((a,b) for a in range(3)) for b in range(3))

…并在必要时转换回列表


2

你会发现 list 的实例没有提供 __hash__ -- 相反,每个列表的该属性实际上是 None(尝试 print [].__hash__)。因此,list 是不可哈希的。

你的代码之所以可以使用 list 而不能使用 set,是因为 set 构建一个无重复项的集合,而列表可以包含任意数据。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接