python中树节点的大量更改字典

python中树节点的大量更改字典,python,dictionary,tree,minimax,Python,Dictionary,Tree,Minimax,我正在尝试实现一个分层树结构,其中每个节点都有一个稍微更改过的字典版本。我的问题是,与R中的类似结构不同,python字典只是外部变量的标签,而不是真正的“值容器”。因此,在其中一个节点上所做的任何更改都会影响所有其他节点的字典 考虑到dict的这种行为,在python中实现它的正确方法是什么?这似乎是一个常见的方法,所以我觉得我一定错过了什么,但我的头撞在墙上已经好几个小时了 背景:我正在尝试用python实现一个基于回合的完美信息对抗棋盘游戏的Minimax方法,使用棋盘状态字典。我根据所有

我正在尝试实现一个分层树结构,其中每个节点都有一个稍微更改过的字典版本。我的问题是,与R中的类似结构不同,python字典只是外部变量的标签,而不是真正的“值容器”。因此,在其中一个节点上所做的任何更改都会影响所有其他节点的字典

考虑到dict的这种行为,在python中实现它的正确方法是什么?这似乎是一个常见的方法,所以我觉得我一定错过了什么,但我的头撞在墙上已经好几个小时了

背景:我正在尝试用python实现一个基于回合的完美信息对抗棋盘游戏的Minimax方法,使用棋盘状态字典。我根据所有可能的移动创建了节点和子节点的层次树结构,到目前为止,我一直在尝试修改每个节点的字典。python中字典的真正本质对我来说并不清楚,因此我一直在与我的方法的奇怪结果作斗争,因为来自每个节点的更改也应用于所有其他节点

示例

#Create some original state (dict of dicts)
state_original = {'field1' : {'player':1, 'count':2}, 'field2' : {'player':2, 'state': 4}}
print(state_original)

#Define object for the tree nodes
class Node(object):
  def __init__(self, depth, state, field=None):
    self.depth = depth
    self.state = state
    self.field = field
    self.subnodes = []
    if self.depth > 0:
      self.SpawnSubnodes()
  def SpawnSubnodes(self):
    for field in self.state:
      depth_new = self.depth -1
      state_new = self.state
      state_new[field]['count'] += 1
      self.subnodes.append(Node(depth_new, state_new, field))

#Build tree
nodes = Node(3, state_original)
nodes.subnodes

#But: This is a mess now
print(state_original)

#This is a mess, too. Results are not meaningful :( 
print(nodes.subnodes[1].state)
它与deepcopy一起工作,但是对于我的(较大的)树来说太慢了

编辑: 我意识到抄袭对我不起作用,因为我的董事会状态是一本字典字典,而不是一本简单的字典。我已经更新了示例代码,以准确地反映这一点。
虽然一个潜在的解决办法是尝试提出一种更简单的电路板表示法(可能将其拆分为“电路板形状”和“电路板状态”两种形式),但我觉得应该有一种更具python风格的方法来解决这个问题?

而不是
copy.deepcopy
,使用
copy.copy
(浅层复制)因为你真的不需要

浅拷贝比深拷贝快得多。下面是一个简单的计时测试:

In [5]: %timeit copy.deepcopy(state_original)
The slowest run took 6.96 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 4.97 µs per loop

In [6]: %timeit copy.copy(state_original)
The slowest run took 8.84 times longer than the fastest. This could mean that an intermediate result is being cached 
1000000 loops, best of 3: 709 ns per loop
注:上述解决方案仅在相关dict简单时有效,即不包含其他dict

如果要开始的dict包含其他简单dict,则迭代地执行其内容的浅拷贝可能比deepcopy操作更快

def mycopy(d):
    return {k: copy.copy(v) for k, v in d.items()}

通过对
mycopy
的初步性能分析,我大致比
copy提高了一个数量级。deepcopy

感谢您编辑注释标记。对不起,这是我第一次发布的问题,我对如何在此处注释行感到困惑。在Python中考虑的一个好的原则是,如果你有一个类,有“代码”、“第二类”、“代码”,还有一种方法可能不需要一个类。杰克·迪德里奇在YouTube上发表了一篇文章。谢谢你的回答!我用我提供的示例代码以及实际的Minimax函数对它进行了测试。对于前者,它可以正常工作,但对于后者,它会导致非法移动,这在使用deepcopy时不会发生。我将深入研究细节,试图找出导致这种行为的原因。因此,我找到了copy.copy在我的实际项目中不起作用的原因:我的董事会状态实际上是一个dict of dict。很抱歉,我的原始示例中没有包含这一点。我想给出一个最低限度的工作示例,目的是为了简单,不知道它会产生如此大的影响。我已经相应地更新了这个问题。@JanLauGe——如果您确定您的板状态不包含3级深嵌套的dict,您可以尝试上面的
mycopy
函数。“mycopy”函数工作起来很有魅力!它甚至比我原来只使用一个字典(因此产生错误)的方法还要快。非常感谢你!
In [5]: %timeit copy.deepcopy(state_original)
The slowest run took 6.96 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 4.97 µs per loop

In [6]: %timeit copy.copy(state_original)
The slowest run took 8.84 times longer than the fastest. This could mean that an intermediate result is being cached 
1000000 loops, best of 3: 709 ns per loop
def mycopy(d):
    return {k: copy.copy(v) for k, v in d.items()}