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

时间:2016-01-02 19:50:11

标签: python dictionary tree 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)

它适用于深度复制,但对于我的(较大的)树来说太慢了

from copy import deepcopy

#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 = deepcopy(self.state)
      state_new[field]['count'] += 1
      self.subnodes.append(Node(depth_new, state_new, field))

修改 我意识到副本对我不起作用,因为我的电路板状态是字典字典而不是简单的字典。我更新了我的示例代码以准确反映这一点。 虽然潜在的解决方法是尝试并提出一个更简单的董事会代表(可能将其分成"董事会形状" dict和"董事会状态" dict),I觉得应该有更多的pythonic方法来解决这个问题?

1 个答案:

答案 0 :(得分:0)

而不是copy.deepcopy,请使用copy.copy(浅层副本),因为您并不真正需要deep copy

import copy

#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 = copy.copy(self.state)
      state_new[field] += 1
      self.subnodes.append(Node(depth_new, state_new, field))

浅拷贝比深拷贝快得多。这是一个简单的时间测试:

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

注意:上述解决方案仅在有问题的词典是 simple 时才有效,即它不包含其他词组。

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

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

mycopy的初步效果分析比copy.deepcopy提供了大约一个数量级的改进。