我正在尝试实现一个分层树结构,其中每个节点都有一个稍微改变的字典版本。我的问题是,与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方法来解决这个问题?
答案 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
提供了大约一个数量级的改进。