You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中自定义类对象可作字典键,列表却不行?相关疑问解析

为什么Python自定义类对象可作为字典键,列表却不行?

先看你提供的测试代码:

class MyClassA:
    def __init__(self, value=0):
        self.value = value

class MyClassB:
    def __init__(self, value=0, list_=[]):
        self.value = value
        self.list = list_
        
a = MyClassA()
b = MyClassB()
c = []

dict_ = {}
dict_[a] = 1 # No error
dict_[b] = 1 # No error
dict_[c] = 1 # TypeError: unhashable type: 'list'

核心原因:字典键必须是可哈希的

Python字典基于哈希表实现,要求键必须满足两个条件:

  1. 实现__hash__()方法,能生成稳定的哈希值
  2. 实现__eq__()方法,能判断两个键是否相等

下面针对你的疑问逐一解释:

1. MyClassA/MyClassB的对象是否为不可变对象?

不是。你可以随时修改它们的属性,比如:

a.value = 100
b.list.append("new item")

对象的内部状态是可变的,但它们依然能当字典键——因为Python给自定义类实例默认提供了__hash__()和__eq__()方法:

  • 默认__hash__()基于对象的内存地址生成哈希值,只要对象没被销毁,内存地址不会变,哈希值就稳定。
  • 默认__eq__()只比较对象的内存地址,只有同一个实例才会被判定为相等。

所以哪怕你修改了对象的属性,它的哈希值和相等性判断逻辑都不会变,字典依然能正常找到对应的键。

2. 列表本身也是对象,为何不可哈希?

因为列表是可变容器,它的内容可以随时被修改(比如append()、pop()、直接修改元素值)。如果允许列表作为字典键,一旦你修改了列表内容,它的哈希值就会改变——而字典是通过哈希值来定位键的位置的,哈希值变化后,原来的键就会“丢失”,破坏字典的一致性。

Python为了避免这种问题,直接让可变类型(列表、字典、集合等)不实现有效的__hash__()方法(或者将__hash__设为None),所以当你试图把列表作为字典键时,就会抛出TypeError: unhashable type: 'list'。

额外补充:如何让自定义类更适合做字典键?

如果想让自定义类的实例成为“安全”的字典键,应该把类设计为不可变的。比如用dataclasses的frozen=True:

from dataclasses import dataclass

@dataclass(frozen=True)
class MyImmutableClass:
    value: int

这样实例的属性无法被修改,同时__hash__()和__eq__()会基于属性值生成,逻辑相等的实例会有相同的哈希值,更符合字典键的预期。

内容的提问来源于stack exchange,提问作者Na Chen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 12:42:59