Python中继承str的类实例为何被转换为str作为字典键?
为什么Python字典会把自定义str子类实例当成普通字符串处理?
这问题得从字典判断键是否重复的核心逻辑说起,咱们一步步拆解清楚:
字典的键匹配核心规则
字典判断两个对象是否属于同一个键,必须同时满足两个条件:
- 两个对象的哈希值(
__hash__()返回值)完全相等 - 两个对象用
==比较时返回True
只要这两个条件都成立,字典就会认定它们是同一个键,后续的赋值操作会直接覆盖原有值,而非新增键值对。
你的SomeClass子类的问题所在
你定义的SomeClass直接继承自str,而且没有重写__hash__和__eq__方法——这意味着它完全复用了str类的哈希计算和相等性判断逻辑:
SomeClass('s').__hash__()和普通字符串's'.__hash__()的结果完全一致SomeClass('s') == 's'会返回True(因为str的__eq__只比较字符串内容,不检查对象类型)
所以当你执行some_dict[s] = 40时,字典检测到s(SomeClass实例)和已有的键's'(普通str)满足上述两个条件,就直接把's'对应的值更新为40,而非新增一个键。
为什么键的类型还是str?
字典在存储键时,只会在第一次添加键的时候保存对应的键对象。后续如果用“等效键”(满足哈希相等+==为True)赋值,字典不会替换掉原来的键对象,只是更新对应的值。你的字典里保留的还是最初添加的str类型的's',这就是type(some_dict.keys()[0])返回str的原因。
怎么让自定义类实例成为独立的键?
如果想让SomeClass实例和普通str作为不同的键,你需要重写__eq__和__hash__方法,打破和普通str的等效性:
class SomeClass(str): def __eq__(self, other): # 仅当other也是SomeClass实例且内容相同时,才判定相等 return isinstance(other, SomeClass) and super().__eq__(other) def __hash__(self): # 在原str哈希值基础上做修改,确保和普通str哈希不同 return super().__hash__() ^ 1 some_dict = {'s':42} s = SomeClass('s') some_dict[s] = 40 print(some_dict) # 输出: {'s': 42, 's': 40} print(type(list(some_dict.keys())[0])) # <class 'str'> print(type(list(some_dict.keys())[1])) # <class '__main__.SomeClass'>
这样就能得到两个独立的键值对了。
内容的提问来源于stack exchange,提问作者Satwik
相关产品推荐
相关产品推荐

