节点哈希与属性匹配但node in children始终为False的问题排查
问题排查与修复方案
我一眼就看出你遇到的问题根源在于相等性判断函数__eq__的实现错误,这直接违反了Python中可哈希对象的核心契约,导致字典的成员检查逻辑失效。咱们一步步拆解:
核心问题:__eq__用身份判断替代值判断
你当前的__eq__实现是:
def __eq__(node1, node2): "节点必须可比较" return node1.board is node2.board
这里的is是判断两个对象的内存地址是否相同(即是否为同一个实例),而不是判断它们的内容是否相等。哪怕两个节点的board数组内容完全一致,只要是不同的对象实例,node1.board is node2.board就会返回False。
但你的__hash__函数是基于board的内容计算的:
def __hash__(self): "节点必须可哈希" return hash(tuple(self.board.flatten() ))
这就造成了一个致命矛盾:
- 内容相同的两个节点,哈希值完全一致(会被字典放到同一个哈希桶里)
- 但因为
__eq__用is判断,它们会被视为不相等
而Python字典的in操作逻辑是:先通过哈希值找到对应的桶,再遍历桶内元素用__eq__判断是否匹配。所以就算哈希匹配,__eq__返回False的话,node in children就会返回False——但node.__eq__(node)肯定是True,因为同一个对象的is判断必然成立。
额外的代码笔误
你的_select函数最后一行还有个明显的错误:
node = choice(tuple(children[unexplored]))
unexplored是一个集合,不能作为字典children的键,这里应该是children[node]吧?不然运行到这里肯定会抛出TypeError。
修复方案
1. 修正__eq__函数,改为值比较
根据你的board是数组的情况,修改成内容相等判断:
def __eq__(self, other): # 先判断类型,避免和非节点对象比较 if not isinstance(other, self.__class__): return False # 如果是numpy数组,用.all()判断所有元素相等;普通列表直接用== return (self.board == other.board).all()
这样只要两个节点的board内容一致,__eq__就会返回True,和__hash__的逻辑保持一致。
2. 修正_select中的笔误
把最后一行改成:
node = choice(tuple(children[node]))
验证修复效果
修复后,内容相同的节点会被字典视为同一个键:
node in children会正确返回True(只要children中存在内容相同的节点)children[node]也能正确找到对应的valueunexplored = children[node] - children.keys()的集合运算也会正常工作,因为集合现在能正确识别内容相同的节点
内容的提问来源于stack exchange,提问作者Saxt
相关产品推荐
相关产品推荐

