如何克服 TypeError: unhash 类型: ‘ list’

我正在尝试获取一个文件,它看起来像这样:

AAA x 111
AAB x 111
AAA x 112
AAC x 123
...

并使用字典使输出看起来像这样

{AAA: ['111', '112'], AAB: ['111'], AAC: [123], ...}

我已经试过了

file = open("filename.txt", "r")
readline = file.readline().rstrip()
while readline!= "":
list = []
list = readline.split(" ")
j = list.index("x")
k = list[0:j]
v = list[j + 1:]
d = {}
if k not in d == False:
d[k] = []
d[k].append(v)
readline = file.readline().rstrip()

我一直收到 TypeError: unhashable type: 'list'。我知道字典中的键不能是列表,但是我试图把我的值变成一个列表,而不是键。我在想我是不是在什么地方犯了错。

845866 次浏览

您试图使用 k(这是一个列表)作为 d的键。列表是可变的,不能用作 dictkey。

此外,你从来没有初始化字典中的列表,因为这一行:

if k not in d == False:

应该是:

if k not in d == True:

实际上应该是:

if k not in d:

发生 TypeError是因为 k是一个列表,因为它是使用来自另一个列表的片段创建的,行为 k = list[0:j]。这可能应该是类似于 k = ' '.join(list[0:j])的东西,所以您使用字符串代替。

除此之外,您的 if语句是不正确的,正如 Jesse 的回答所指出的那样,应该读作 if k not in dif not k in d(我更喜欢后者)。

因为在 for循环中有 d = {},所以在每次迭代中都要清除字典。

请注意,您也不应该使用 listfile作为变量名,因为您将屏蔽内置函数。

下面是我将如何重写您的代码:

d = {}
with open("filename.txt", "r") as input_file:
for line in input_file:
fields = line.split()
j = fields.index("x")
k = " ".join(fields[:j])
d.setdefault(k, []).append(" ".join(fields[j+1:]))

上面的 dict.setdefault()方法取代了代码中的 if k not in d逻辑。

正如其他答案所指出的那样,错误是由于 k = list[0:j]造成的,在 k = list[0:j]中,您的密钥被转换为一个列表。您可以尝试重新编写代码以利用 split函数:

# Using with ensures that the file is properly closed when you're done
with open('filename.txt', 'rb') as f:
d = {}
# Here we use readlines() to split the file into a list where each element is a line
for line in f.readlines():
# Now we split the file on `x`, since the part before the x will be
# the key and the part after the value
line = line.split('x')
# Take the line parts and strip out the spaces, assigning them to the variables
# Once you get a bit more comfortable, this works as well:
# key, value = [x.strip() for x in line]
key = line[0].strip()
value = line[1].strip()
# Now we check if the dictionary contains the key; if so, append the new value,
# and if not, make a new list that contains the current value
# (For future reference, this is a great place for a defaultdict :)
if key in d:
d[key].append(value)
else:
d[key] = [value]


print d
# {'AAA': ['111', '112'], 'AAC': ['123'], 'AAB': ['111']}

请注意,如果您使用的是 Python 3.x,那么您将不得不进行一些小的调整以使其正常工作。如果使用 rb打开文件,则需要使用 line = line.split(b'x')(确保使用适当类型的字符串分割字节)。您也可以使用 with open('filename.txt', 'rU') as f:(甚至 with open('filename.txt', 'r') as f:)打开该文件,它应该可以正常工作。

之所以会出现 unhashable type: 'list'异常,是因为 k = list[0:j]k设置为列表的“片”,这在逻辑上是另一个通常较短的列表。你需要的是得到列表中的第一个项目,像 k = list[0]这样写。对于调用 readline.split(" ")返回的列表的第三个元素,v = list[j + 1:]也应该是 v = list[2]

我注意到了代码中其他几个可能的问题,我将提到其中的一些。一个大问题是,您不希望(重新)对循环中读取的每一行使用 d = {}初始化 d。另一个问题是,将变量命名为与任何内置类型相同的变量通常都不是一个好主意,因为这会阻碍您在需要时访问其中一个变量ーー而且会让习惯于使用这些标准项目名称的人感到困惑。出于这个原因,您应该将变量 list重命名为不同的名称,以避免类似的问题。

这是一个带有这些修改的工作版本,我还替换了以前用来检查键是否已经在字典中的 if语句表达式,现在使用字典的 setdefault()方法来更简洁地完成同样的事情。

d = {}
with open("nameerror.txt", "r") as file:
line = file.readline().rstrip()
while line:
lst = line.split() # Split into sequence like ['AAA', 'x', '111'].
k, _, v = lst[:3]  # Get first and third items.
d.setdefault(k, []).append(v)
line = file.readline().rstrip()


print('d: {}'.format(d))

产出:

d: {'AAA': ['111', '112'], 'AAC': ['123'], 'AAB': ['111']}
    python 3.2


with open("d://test.txt") as f:
k=(((i.split("\n"))[0].rstrip()).split() for i in f.readlines())
d={}
for i,_,v in k:
d.setdefault(i,[]).append(v)

注: 这个答案没有明确回答问题。其他的答案也一样。由于问题是具体的 变成了一个场景和提出的 例外是一般的,这个答案指向一般情况。

散列值只是整数,用于在字典查找过程中快速比较字典键。

在内部,hash()方法调用对象的 __hash__()方法,该方法默认为任何对象设置。

转换 集合的嵌套列表

>>> a = [1,2,3,4,[5,6,7],8,9]
>>> set(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

这是因为列表中的列表是一个不能被散列的列表。这个问题可以用 将内部嵌套列表转换为元组来解决,

>>> set([1, 2, 3, 4, (5, 6, 7), 8, 9])
set([1, 2, 3, 4, 8, 9, (5, 6, 7)])

显式散列 一个嵌套的列表

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




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


>>> hash(tuple([1, 2, 3, tuple([4, 5,]), 6, 7]))
-7943504827826258506

避免此错误的解决方案是重新构造列表,使其具有嵌套元组而不是列表。

这背后的原因是列表包含值的列表。例如:

a = [[1,2],[1,2],[3,4]]

这种情况下是行不通的:

list(set(a))

为了解决这个问题,你可以将内部列表转换为 tuple,比如:

a = [(1,2),(1,2),(3,4)]

会成功的!