python 链接结构 - 将子节点插入节点 A 的父节点也插入到节点 A
python linked structure - inserting child to node A's parent is also inserting to node A
我正在尝试使用 python 为树实现链接结构
这是我的代码的摘录
class Node(object):
def __init__(self,value,father=None,children=[]):
self.value=value
self.father=father
self.children=children
def __str__(self):
return self.value
class Tree(object):
def __init__(self,root=None):
self.root=root
def insertNode(self,new_node,father_value):
father_node=self.find_node(father_value)
if not father_node:
return False
new_node.father=father_node
print("Node's information BEFORE adding child to father's list of children")
print(f"Father node (find) {father_node}")
print(f"Father node's children {[x.value for x in father_node.children]}")
print(f"New node's father {new_node.father}")
print(f"New node's children {[x.value for x in new_node.children]}")
father_node.children.append(new_node)
print("Node's information AFTER adding child to father's list of children")
print(f"Father node (find) {father_node}")
print(f"Father node's children {[x.value for x in father_node.children]}")
print(f"New node's father {new_node.father}")
print(f"New node's children {[x.value for x in new_node.children]}")
def find_node(self,value):
stack=[self.root]
while True:
if len(stack)==0:
return False
node=stack.pop()
if node.value==value:
return node
children=node.children
stack.extend(children)
n1=Node("A")
tree=Tree(n1)
tree.insertNode(Node("B"),"A")
n1=Node("A")
tree=Tree(n1)
tree.insertNode(Node("B"),"A")
输出是
Node's information BEFORE adding child to father's list of children
Father node (find) A
Father node's children []
New node's father A
New node's children []
Node's information AFTER adding child to father's list of children
Father node (find) A
Father node's children ['B']
New node's father A
New node's children ['B']
如您所见,当我将新插入的节点追加到父亲的子节点列表中时,它也会插入到新节点的子节点列表中。如何解决这个问题?
问题的发生是因为 Python 如何处理函数的可选参数的默认值。
在 class Node(object)
中,您有这一行:
def __init__(self,value,father=None,children=[]):
Python只计算默认值[]
一次(创建一个空的list
object),然后重用该评估值(引用 list
object)对于该函数的所有后续调用。
在您的例子中,函数是 __init__()
函数,每次实例化 Node
class 时都会调用该函数。如果您多次实例化 Node
而没有显式传递第三个参数,则在 __init__()
的所有这些调用中,参数 children
将被分配 相同的 list
object 作为默认值。您正在使用此值来设置所有这些实例的 children
属性。换句话说,对于所有这些 Node
实例,children
属性将指向相同的 list
object。这就是为什么将 child 插入“父亲”Node
也会将相同的 child 添加到当前的 Node
.
re-write __init__()
的正确方法是:
class Node(object):
def __init__(self,value,father=None,children=None):
self.value=value
self.father=father
self.children=children if children is not None else []
道德
这里的一般寓意是,如果您的参数的默认值是 可变 object,它可能会引发这样的意外——您不知道的地方,多个引用存储到单个 object,并且通过一个引用对 object 的突变(更改)也将通过其他引用反映(看到)。
这一切都记录在案here
我正在尝试使用 python 为树实现链接结构 这是我的代码的摘录
class Node(object):
def __init__(self,value,father=None,children=[]):
self.value=value
self.father=father
self.children=children
def __str__(self):
return self.value
class Tree(object):
def __init__(self,root=None):
self.root=root
def insertNode(self,new_node,father_value):
father_node=self.find_node(father_value)
if not father_node:
return False
new_node.father=father_node
print("Node's information BEFORE adding child to father's list of children")
print(f"Father node (find) {father_node}")
print(f"Father node's children {[x.value for x in father_node.children]}")
print(f"New node's father {new_node.father}")
print(f"New node's children {[x.value for x in new_node.children]}")
father_node.children.append(new_node)
print("Node's information AFTER adding child to father's list of children")
print(f"Father node (find) {father_node}")
print(f"Father node's children {[x.value for x in father_node.children]}")
print(f"New node's father {new_node.father}")
print(f"New node's children {[x.value for x in new_node.children]}")
def find_node(self,value):
stack=[self.root]
while True:
if len(stack)==0:
return False
node=stack.pop()
if node.value==value:
return node
children=node.children
stack.extend(children)
n1=Node("A")
tree=Tree(n1)
tree.insertNode(Node("B"),"A")
n1=Node("A")
tree=Tree(n1)
tree.insertNode(Node("B"),"A")
输出是
Node's information BEFORE adding child to father's list of children
Father node (find) A Father node's children [] New node's father A New node's children [] Node's information AFTER adding child to father's list of children Father node (find) A Father node's children ['B'] New node's father A New node's children ['B']
如您所见,当我将新插入的节点追加到父亲的子节点列表中时,它也会插入到新节点的子节点列表中。如何解决这个问题?
问题的发生是因为 Python 如何处理函数的可选参数的默认值。
在 class Node(object)
中,您有这一行:
def __init__(self,value,father=None,children=[]):
Python只计算默认值[]
一次(创建一个空的list
object),然后重用该评估值(引用 list
object)对于该函数的所有后续调用。
在您的例子中,函数是 __init__()
函数,每次实例化 Node
class 时都会调用该函数。如果您多次实例化 Node
而没有显式传递第三个参数,则在 __init__()
的所有这些调用中,参数 children
将被分配 相同的 list
object 作为默认值。您正在使用此值来设置所有这些实例的 children
属性。换句话说,对于所有这些 Node
实例,children
属性将指向相同的 list
object。这就是为什么将 child 插入“父亲”Node
也会将相同的 child 添加到当前的 Node
.
re-write __init__()
的正确方法是:
class Node(object):
def __init__(self,value,father=None,children=None):
self.value=value
self.father=father
self.children=children if children is not None else []
道德
这里的一般寓意是,如果您的参数的默认值是 可变 object,它可能会引发这样的意外——您不知道的地方,多个引用存储到单个 object,并且通过一个引用对 object 的突变(更改)也将通过其他引用反映(看到)。
这一切都记录在案here