Python,TypeError:不可哈希类型:'list'

107
我的程序出现了以下错误。回溯信息如下:
Traceback (most recent call last):
File "C:\Python33\Archive\PythonGrafos\Alpha.py", line 126, in <module>
menugrafos()
File "C:\Python33\Archive\PythonGrafos\Alpha.py", line 97, in menugrafos
zetta = Beta.caminhografo(grafo,va,vb)
File "C:\Python33\Archive\PythonGrafos\Beta.py", line 129, in caminhografo
if ([vo, a]) in vat == ([vo,vq]) in vat:
TypeError: unhashable type: 'list'

该程序旨在创建一个邻接表,这一部分运行良好,然后继续搜索顶点va和vb之间是否存在路径。我使用了一个列表字典来适当地附加相邻的顶点。

问题出现在程序末尾创建列表后的if语句中。我找不到一种正确使用字典的if语句的方法来查看顶点之间是否存在有效路径。此外,grafo是一个图形类。

以下是代码:

class graph:
    v = 0
    a = 0
    node = []

class vertex:
    ta = []
    adj = {}
    
def caminhografo(grafo, va, vb):
    vat = defaultdict(list)
    i = 0
    a = 0
    z = 0
    vo = int(va)
    vq = int(vb)
    vz = int(va)
    vw = int(vb)
    x = len(grafo.node)
    if vz < vw:
        for vz in range (vw+1):
            a = 0
            x = len(grafo.node)
            for a in range (x):
                if [int(vz),int(a)] in grafo.node:
                    vat[vz].append(a)                   
    if vz > vw:
        while vz > vw:
            a = 0
            x = len(grafo.node)
            for a in range (x):
                if[int(va),int(a)] in grafo.node:
                    vat[vz].append(a)
            vz = vz - 1
    a = 0
    x = len(grafo.node)
    print(vat)
    for a in range (x):
       if ([vo, a]) in vat == ([vo,vq]) in vat:
           print("""
    ==============================================
               Existe Caminho
    ==============================================
    """)
           break
       elif ([vo,a]) in vat:
           vo = a
       else:           
           print("""
    ==============================================
             Não Existe Caminho
    ==============================================
        """)
           break
2个回答

169
问题在于你不能将列表用作字典的键,因为字典的键必须是不可变的。使用元组代替。
这是一个列表:
[x, y]

这是一个元组:

(x, y)

请注意,在大多数情况下,()是可选的,因为,实际上才是定义元组的符号(只要它不被[]{}包围,或者用作函数参数)。
您可能会发现Python教程中有关元组的部分很有用:
虽然元组看起来与列表相似,但它们通常在不同的情况和不同的目的中使用。元组是不可变的,并且通常包含异构序列的元素,可以通过解包(请参见本节后面)或索引(甚至在命名元组的情况下也可以通过属性)访问这些元素。列表是可变的,它们的元素通常是同质的,并通过迭代列表进行访问。
字典的部分中:
与序列不同,字典是由键索引的,这些键可以是任何不可变类型;字符串和数字始终可以作为键。如果元组只包含字符串、数字或元组,则可以将其用作键;如果元组直接或间接地包含任何可变对象,则不能将其用作键。无法使用列表作为键,因为列表可以使用索引赋值、切片赋值或像append()和extend()这样的方法进行就地修改。

如果你不明白这个错误信息的含义,那是因为列表没有内置的哈希函数(这是设计如此),而字典是通过哈希表实现的。


那么元组只会被读取为键吗?如果我正在寻找 (key1, element_in_key),它就不能工作了吗? - Rex
@Rex 回答你的问题最简单的方法可能是在Python解释器中尝试一些东西。简而言之,如果你存储了一个键,比如 some_dict[key] = something,那么 key in some_dict 就会是真的。这与键是什么无关(只要它是可哈希的)。 - Brendan Long
那么,通过使用列表字典,我会阻止自己从if语句中的键获取列表值吗?在这种情况下,我的if语句永远不会成立,因为我正在寻找一个可变变量?因此,最好使用另一种格式来存储顶点的邻接关系。 - Rex
我明白,但即使我玩弄()[],如(a,[b]),if语句仍然被忽略了。我不知道为什么它不起作用。 - Rex
@Rex 如果你的代码运行时没有抛出异常,那么这个问题就已经得到了回答。请为你的新问题创建一个新的问题。在评论中回答后续问题非常困难,并且会阻止其他网站成员帮助你。 - Brendan Long
显示剩余9条评论

2
如果您看到这篇文章是因为遇到了标题中的错误,除了 OP 的问题(其中一个列表被用作字典的键),还有几种情况可能会出现这种错误。
1. 一个列表被传递到了一个集合中
就像列表不能成为字典键一样,列表也不能成为集合元素。如果要添加一个元组,它也不应该包含一个列表。
s = {(1, 2), [3, 4]}    # <---- TypeError: unhashable type: 'list'
s = {(1, 2), (3, 4)}    # <---- OK

s.add((5, [6]))         # <---- TypeError because the element to be added contains a list
s.add((5, 6))           # <---- OK because (5, 6) is a tuple
2. Pandas列表分组

另一种常见的错误发生在pandas数据框列存储列表并用作groupby操作中的分组器时。解决方法与上述类似,将列表转换为元组,并使用元组列进行分组。

import pandas as pd
df = pd.DataFrame({'group': [[1, 2], [3, 4], [5, 6]], 'value': [0, 1, 2]})

# group  value
# [1, 2]     0
# [3, 4]     1
# [5, 6]     2

df.groupby('group')['value'].mean()                  # <---- TypeError
df.groupby(df['group'].agg(tuple))['value'].mean()   # <---- OK
#          ^^^^^^^^^^^^^^^^^^^^^^  <--- convert each list into a tuple
3. Pandas索引/列标签包含列表

Pandas的列标签不能是一个列表(因为它类似于字典键),因此,如果您尝试通过列表对它进行rename(),它将显示此错误。一种解决方法是将列表转换为元组(甚至转换为MultiIndex)。

df = pd.DataFrame({'group': range(3)})
df.rename(columns={'group': ['col', 'one']})               # TypeError
df.rename(columns={'group': ('col', 'one')})               # OK
df.columns = pd.MultiIndex.from_tuples([('col', 'one')])   # OK


Pandas的索引可以包含列表作为值,但如果您尝试对该行进行索引,它将抛出此错误。解决方案是将列表转换为元组或简单地“清理”数据(可能索引一开始就不应该包含列表/元组),例如将其转换为MultiIndex。
df = pd.DataFrame({'group': range(3)}, index=[['a'], 'b', 'c'])
df.loc['b']           # TypeError
4. 在包含列表的对象上调用collections.Counter

由于Counter创建了一个类似字典的对象,每个值都应该是不可变的,因此如果一个对象包含一个列表,就会出现这个错误。解决方案可能是将列表转换为元组。

from collections import Counter
lst = ['a', 'b', ['c']]
Counter(lst)                  # TypeError

Counter(['a', 'b', ('c',)])   # OK

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