在python中编写一些脚本时,我编写了一个简单的类树结构。在测试之后,我得到了一个奇怪但有趣的结果;
假设我们实现了一个简单的树,每个节点都有一个子节点。然后,我们可以像这样实现它:
class node_1(object):
def __init__(self, data = 0, child = None):
self.data = data
self.child = child
def append(self, child):
self.child = child
def __str__(self):
return '(box %s)' % str(self.data)
def __repr__(self):
return self.__str__()
当我们执行以下代码时:
root_1 = node_1(0)
root_1.append(node_1(1))
root_1.child.append(node_1(2))
print root_1, root_1.child, root_1.child.child
我们得到以下结果,我们期望:
(box 0) (box 1) (box 2)
现在让我们假设每个节点可以有多个子节点;如果我们像下面的代码那样实现它:
class node_2(object):
def __init__(self, data = 0, childs = []):
self.data = data
self.childs = childs
def append(self, *childs):
map(self.childs.append, childs)
def __str__(self):
return '(box %s)' % str(self.data)
def __repr__(self):
return self.__str__()
然后是代码
root_2 = node_2(0)
root_2.append(node_2(1), node_2(2))
root_2.childs[0].append(node_2(3), node_2(4))
print root_2, root_2.childs, root_2.childs[0].childs
输出
(box 0) [(box 1), (box 2), (box 3), (box 4)] [(box 1), (box 2), (box 3), (box 4)]
,而不是
(box 0) [(box 1), (box 2)] [(box 3), (box 4)]
我猜测这与可迭代对象中项目的引用有关,但我无法弄清楚子节点的原因(精确)。 self.childs不仅包含它们的子节点,还包含兄弟节点甚至父节点。你能帮我理解为什么会出现这个结果吗?
(完整代码:https://github.com/Avantgarde95/share/blob/master/btest.py)
[解决]
感谢他们提供的以及他提供的链接,我可以理解问题是由孩子= []'声明。根据链接,只有当python遇到' def'时,才会(重新)评估默认参数。关键词;所以,如果我设置默认参数' childs'在第一次调用self.append之后,一个可变对象(例如list),节点的所有self.childs将指向同一个对象。
以下代码现在运作良好:
class node(object):
def __init__(self, data = 0, childs = None):
self.data = data
if childs is None:
self.childs = []
else:
self.childs = child
def append(self, *childs):
map(self.childs.append, childs)
def __str__(self):
return '(box %s)' % str(self.data)
def __repr__(self):
return self.__str__()
执行
root = node(0)
root.append(node(1), node(2))
root.childs[0].append(node(3), node(4))
print root, root.childs, root.childs[0].childs
给出
(box 0) [(box 1) (box 2)] [(box 3) (box 4)]