2016-11-13 174 views
-1

我在Python中创建了一个图节点类。
每个节点都有单亲,多个孩子和属性。
的实现应该有如下:python对象具有初始化属性

# graph_test.py 
class Node(object): 
    def __init__(self, name, prop={}): 
     self.name = name 
     self.properties = prop 
     self.parent = None 
     self.children = [] 
     print "New node:", self.name, self.properties 
    def add_prop(self, k, v): 
     self.properties.update({k:v}) 
     print "added prop:", k, v 
    def add_child(self, n): 
     self.children.append(n) 
     n.parent = self 

class Foo(object): 
    def __init__(self, n): 
     self.node_num = n 
     self.root_node = None 
     self.current_node = None 
    def bas(self): 
     n = Node("root") 
     n.add_prop("this_prop_is", "set_only_root_node") 
     self.root_node = n 
     return self.root_node 
    def bar(self): 
     self.current_node = self.bas() 
     for i in range(self.node_num): 
      n = Node(str(i)) 
      self.current_node.add_child(n) 
      self.current_node = n 

if __name__ == '__main__': 
    f = Foo(5) 
    f.bar() 

在这段代码中,预计只有根节点,其关键是“this_prop_is”的属性。
然而,执行的结果是象下面这样:

$ python ./graph_test.py 
New node: root {} 
added prop: this_prop_is set_only_root_node 
New node: 0 {'this_prop_is': 'set_only_root_node'} 
New node: 1 {'this_prop_is': 'set_only_root_node'} 
New node: 2 {'this_prop_is': 'set_only_root_node'} 
New node: 3 {'this_prop_is': 'set_only_root_node'} 
New node: 4 {'this_prop_is': 'set_only_root_node'} 

所有节点具有相同的钥匙,甚至我把它添加到仅节点的“根”。我使用python 2.7.6

我的问题是:

  • 这是一个错误?
  • 如果这不是一个错误,为什么会发生这种情况?
  • 如何解决这个问题?

回答

2

这不是一个错误。问题是您的默认值prop。您将其设置为空字典。但是,该空字典通过引用self.properties = prop进行复制,并且在修改该字典时,下次创建新的Node时,修改过的字典将用作默认值。

为了解决这个问题,把无作为默认值,并检查无指定属性时:

# graph_test.py 
class Node(object): 
    def __init__(self, name, prop=None): 
     self.name = name 
     self.properties = prop or {} 
     self.parent = None 
     self.children = [] 
     print "New node:", self.name, self.properties 
    def add_prop(self, k, v): 
     self.properties.update({k:v}) 
     print "added prop:", k, v 
    def add_child(self, n): 
     self.children.append(n) 
     n.parent = self 

class Foo(object): 
    def __init__(self, n): 
     self.node_num = n 
     self.root_node = None 
     self.current_node = None 
    def bas(self): 
     n = Node("root") 
     n.add_prop("this_prop_is", "set_only_root_node") 
     self.root_node = n 
     return self.root_node 
    def bar(self): 
     self.current_node = self.bas() 
     for i in range(self.node_num): 
      n = Node(str(i)) 
      self.current_node.add_child(n) 
      self.current_node = n 

if __name__ == '__main__': 
    f = Foo(5) 
    f.bar() 
+0

谢谢。在C++中,每个函数调用都会对默认参数进行评估,所以它很混乱...... – furushchev

1

这是因为您在Node.__init__中有一个可变的默认值。在Python中,默认值是在创建函数时确定的,并且始终使用相同的实例。因此,每次创建新的Node并且不要给出明确的prop参数时,它将使用相同的字典。

这通常是通过使用None作为默认值,并在函数内部每次创建一个新的字典,如果参数为None,例如做self.properties = prop or {}解决。 (这也将使用一个新的字典,如果你给它一个空的字典,但这不是通常有问题)

0

变化props={}props=Noneself.properties = propself.properties = prop or {}

这是由于可变违约行为Python中的参数。这里有一个很好的资源来阅读:http://effbot.org/zone/default-values.htm