Python构建对齐对映射字典触发TypeError: unhashable type: 'list'问题咨询
报错根因
Python 字典的键必须是可哈希类型:即实现了不可变哈希协议的对象(如字符串、数字、元素全为可哈希类型的元组)。而 list 是可变类型,没有实现可哈希接口,因此当你把嵌套了 list 的对齐元组作为字典键时,就会触发TypeError: unhashable type: 'list'错误。
除此之外原有代码存在两个隐藏问题:
- 判定
substitution的分支条件逻辑错误:i[0] != i[1] and i[0] == "-" and i[1] == "-"永远不可能成立(两个元素都是-时必然相等),替换标签的分支完全不会触发 - 直接用
len()判断元素长度的逻辑缺少类型校验,碰到多字符字符串时会被误判为一对多/多对一的对齐类型
可落地的修正方案
方案1:最小改动,将嵌套list替换为元组
元组是不可变可哈希类型,和list的使用体验几乎一致,仅需把原始对齐对里的列表元素替换为元组,同时修正错误的判断分支即可:
l = [ ("d", "d"), ("t", "-"), ("-", "t"), ("f", "d"), ("æ", ("ɑ", "ɪ")), # 原列表替换为元组 (("ɑ", "ɪ"), "æ"), # 原列表替换为元组 ] labels = [ "perfect", "deletion", "insertion", "substitution", "one-to-many", "many-to-one", ] align_label_map = {} # 避免用dict作变量名覆盖内置类型 for pair in l: left, right = pair if left == right: align_label_map[pair] = labels[0] elif right == "-": align_label_map[pair] = labels[1] elif left == "-": align_label_map[pair] = labels[2] # 修正替换标签的判断逻辑:左右都不是占位符、且值不相等 elif left != right and left != "-" and right != "-": align_label_map[pair] = labels[3] # 增加类型校验,避免多字符字符串被误判 elif isinstance(right, (tuple, list)) and len(right) >= 2: align_label_map[pair] = labels[4] elif isinstance(left, (tuple, list)) and len(left) >= 2: align_label_map[pair] = labels[5]
运行后得到的字典可以完整覆盖所有6类对齐场景,且不会触发可哈希类型错误。
方案2:保留原始带list的输入结构,将键做可哈希转换
如果原始对齐数据是上游传入的固定结构、无法修改内部的list元素,可以在存储字典键时,将整个对齐对序列化为字符串形式(字符串是天然可哈希类型),从根源上规避list不可哈希的问题:
import json l = [ ("d", "d"), ("t", "-"), ("-", "t"), ("f", "d"), ("æ", ["ɑ", "ɪ"]), (["ɑ", "ɪ"], "æ"), ] labels = [ "perfect", "deletion", "insertion", "substitution", "one-to-many", "many-to-one", ] align_label_map = {} for pair in l: left, right = pair # 将对齐对序列化为带中文支持的字符串作为字典键 dict_key = json.dumps(pair, ensure_ascii=False) if left == right: align_label_map[dict_key] = labels[0] elif right == "-": align_label_map[dict_key] = labels[1] elif left == "-": align_label_map[dict_key] = labels[2] elif left != right and left != "-" and right != "-": align_label_map[dict_key] = labels[3] elif isinstance(right, list) and len(right) >= 2: align_label_map[dict_key] = labels[4] elif isinstance(left, list) and len(left) >= 2: align_label_map[dict_key] = labels[5]
后续查询标签时,只需把待查询的对齐对用相同的json.dumps方法序列化,就能从字典中取到对应标签。
注意事项
- 不要用
dict、list这类Python内置类型名作为自定义变量名,否则会覆盖内置对象的全局引用,后续代码调用内置类型时容易出现难以排查的问题 - 做长度判断增加
isinstance类型校验,避免因为输入类型变化(比如多字符字符串)导致的逻辑误判
内容的提问来源于stack exchange,提问作者Sayed Sabry
相关产品推荐
相关产品推荐

