2016-11-13 243 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