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

自定义__eq__和__hash__后,Python字典为何出现重复键?

Q表出现重复键的原因及修复方案

你遇到的问题根源在于State对象的data属性是可变的列表,且这些列表在State被作为字典键存入后仍被修改,导致字典无法正确识别原本应该相等的键。

具体分析

  • 你的ToyMDP中,每次创建State时传入的是self.toy.buttons(一个列表),这个列表的引用会被存在State.data中。
  • 在Toy.press方法中,会直接修改当前self.toy.buttons列表的元素(self.buttons[button] = 1 - self.buttons[button]),这会导致已经创建的State对象的data内容被意外修改。
  • 当State对象作为键存入q_func后,它的哈希值(依赖于data内容)和相等性判断会发生变化。字典在存入时是根据当时的哈希值分配bucket的,后续哈希值变化后,字典无法将修改后的State与之前存入的键关联,导致新的相等键被当成新条目存入,最终出现大量重复。

修复方案

方案1:使用不可变对象作为State的data

将传入State的列表转换为不可变的tuple,确保State对象的哈希和相等性不会后续变化:

  1. 修改ToyMDP.__init__中的初始状态创建:
init_state = State(data=tuple(self.toy.buttons))
  1. 修改ToyMDP._transition_func中的新状态创建:
new_state = State(tuple(self.toy.buttons))

方案2:修改State类确保data不可变

如果无法修改MDP代码,可以在State类的初始化中自动将可变序列转为不可变类型:

class State:
    def __init__(self, data=[]):
        # 将列表转为元组,确保不可变
        if isinstance(data, list):
            self.data = tuple(data)
        elif type(data).__module__ == np.__name__:
            # 对于numpy数组,转为扁平化元组
            self.data = tuple(data.flatten())
        else:
            self.data = data
    
    # 保留原有的__eq__和__hash__方法
    def __eq__(self, other):
        if isinstance(other, State):
            return self.data == other.data
        return False

    def __hash__(self):
        if type(self.data).__module__ == np.__name__:
            return hash(str(self.data))
        elif self.data.__hash__ is None:
            return hash(tuple(self.data))
        else:
            return hash(self.data)

额外修复:完善MDP的reset方法

你的ToyMDP没有重写reset方法,导致每次episode结束后self.toy的状态不会重置,可能引发其他逻辑问题。添加reset方法:

class ToyMDP(MDP):
    # ... 其他已有代码 ...
    def reset(self):
        self.toy = Toy()
        self.init_state = State(data=tuple(self.toy.buttons))
        self.set_current_state(self.init_state)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 17:17:06