furushchev furushchev - 20 days ago 6
Python Question

python object has properties on initialze

I created a graph node class in Python.

Each node has single parent, multiple children and properties.

An implementation should be like below:

# 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()


In this code, it is expected that only the root node has the property whose key is "this_prop_is".

However, result of execution is like below:

$ 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'}


All nodes have the same key even I add it to only node "root".

I use
python 2.7.6
.

My questions are:


  • Is this a bug?

  • If this is not a bug, why does this occur?

  • How to fix this issue?


Answer

This is not a bug. The problem is your default value for prop. You set it as an empty dictionary. However, this empty dictionary is copied by reference with self.properties = prop and when it is modified, the next time a new Node is created, the modified dictionary is used as the default value.

To fix this, put None as the default value and check for None when assigning properties:

# 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()
Comments