I am trying to write a node class to create a tree structure. There seems to be
some problem when I'm trying to add a child node to the root node with the method "addChild" because the child node appears to have itself in its children list. I couldn't figure out why, so any help is appreciated.
class node(object):
def __init__(self, name, x, y, children = []):
self.name = name
self.children = children
self.x = x
self.y = y
def addChild(self):
b=node('b', 5, 5)
self.children.append(b)
return
root=node('a',0.,0.)
print root.children
root.addChild()
print root.children
print root.children[0].children
Yields:
[<__main__.node object at 0x7faca9f93e50>]
[<__main__.node object at 0x7faca9f93e50>]
Whereas the second "print" line should have returned an empty array.
The default parameter value children = [] assigns a single list object to the __init__ function that is then used on every call all children. This is a common mistake. Instead, create children in the __init__ function itself:
class node(object):
def __init__(self, name, x, y, children=None):
self.name = name
self.children = [] if children is None else children
self.x = x
self.y = y
# ...
Related
Does anyone know how i can get the name of an object with a class function?
I want to use this because i have a class that is supposed to have multiple players in a list, and get their cordinates
object that wants to give their cordinates:
import math
class Pixel:
"""Represents a posision in a grid with a x posistion, a y position and
a character, the x and y position are saved in one tuple"""`
def __init__(self, char='#', pos=(0, 0)):
assert type(char) == str
assert type(pos[0]) == int and type(pos[1]) == int
self.pos = pos
self.x = self.pos[0]
self.y = self.pos[1]
self.char = char
def __str__(self):
return self.char
def __repr__(self):
return self.char
# possible debug repr 'Pixel object with
# char = ' + str(self.char) + ' and pos = ' + str(self.pos)`
class TestObject(Pixel):
def __str__(self, parent):
return '+'
The parent object wants to know what self.pos is from theTestObject (the parent has a list with different testObjects) is there a way for me to give the TestObject the name of the parent object when i am creating it so that he can push that information (parent.funcname(position)) I need it for a function that doesn't return values.
if anyone knows another way to get TestObject.pos to my parent object please tell too, thanks in advance
You could give your instances of TestObject a reference to the parent. This could be done via the __init__ method of TestObject. This way however, the parent has to be known at the time of the instance's construction. I would make it an optional (keyword) parameter and implement a setter method. For example:
class Pixel:
def __init__(self, char='#', pos=(0, 0), parent=None):
assert type(char) == str
assert type(pos[0]) == int and type(pos[1]) == int
self.pos = pos
self.x = self.pos[0]
self.y = self.pos[1]
self.char = char
self._parent = parent
def set_parent(self, parent):
self._parent = parent
class TestObject(Pixel):
def somemethod(self):
position = 0
# do what ever you need to do here
if isinstance(self._parent, Pixel):
self._parent.set_value(self)
When you add an instance obj of TestObject to the list in the parent object, the parent object should call obj.set_parent(self) to set itself as the object's parent.
Here is an example for a parent class:
class PixelList:
def __init__(self):
self._pixels = []
def add_pixel(self, pixel):
self._pixels.append(pixel)
pixel.set_parent(self)
def set_value(self, pixel):
# do stuff here
position = pixel.pos
If you then call obj.somemethod, your parent object's set_value method is called with the pixel as argument. In the set_value method you can thus access any information of the pixel you like (e.g. pixel.pos).
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?
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()
This is because you have a mutable default value in Node.__init__. In Python, default values are determined when the function is created, and the same instance will always be used. So every time you create a new Node and don't give it an explicit prop argument, it will use the same dictionary.
This is often solved by using None as the default value and creating a new dictionary each time inside the function if the argument is None, for example by doing self.properties = prop or {}. (This will also use a new dictionary if you give it an empty dictionary, but this isn't usually a problem)
Change props={} to props=None and self.properties = prop to self.properties = prop or {}
This is due to the behavior of mutable default arguments in Python. Here's a good resource to read up on this: http://effbot.org/zone/default-values.htm
I have a problem with a self-written tree class in python:
class Tree:
def __init__(self, parent=0, value=0):
self.value = value
self.parent = parent
def __iter__(self): return self
def next(self):
tmp = self.value
try:
self.parent = self.parent.parent
self.value = self.parent.value
except AttributeError:
raise StopIteration
return tmp
def sum(self):
list_ = [item for item in self]
print list_
return sum(list_)
Actually, the "tree" is not fully written, but the current problem blocks further progress.
The structure has only two instance variables (value, parent).
I would like to sum values from the current instance to the first parent with iterators (if it is all together possible). The sum method is used for that (additional list_ variable is unnecessary, but helps further to explain the problem).
When running a test case
parent = Tree()
child = Tree(parent=parent, value=8)
child2 = Tree(parent=child,value=10)
print child2.sum()
I obtain the following:
[10]
10
Please, could anybody explain why the list of values contains only one number though it should look like [10,8]? Seems the problem is in the implementation of iter and next, but I can't understand how to repair the solution.
Thank you in advance.
I'm not sure you can call this a Tree. One would expect parent node(s) and multiple leaf nodes, and not just a linear connection of objects.
See: A general tree implementation?
On another note, if you want to implement a linkedlist, suggestions made in the comment to your question by Barny should be considered and as well, you can give an eye to: Python Linked List
Coming to your current implementation, you'll need some sort of loop, to walk from the current child node up until the head parent node. And when the next parent attribute is not found, stop the iteration. The following puts the logic in the __iter__ method of the class, which is now a generator function:
class Tree:
def __init__(self, parent=None, value=0):
self.value = value
self.parent = parent
def __iter__(self):
_parent = self.parent
yield self.value
while True:
try:
yield _parent.value
_parent = _parent.parent
except AttributeError:
break
def sum_from_node(self):
list_ = [item for item in self]
print list_
return sum(list_)
Demo:
parent = Tree()
child = Tree(parent=parent, value=8)
child2 = Tree(parent=child,value=10)
child3 = Tree(parent=child2,value=4)
print child3.sum_from_node()
# [4, 10, 8, 0]
# 22
Here you go:
class Tree:
def __init__(self, parent=None, value=0):
self.value = value
self.parent = parent
def __iter__(self):
yield self.value
root = self
while root.parent is not None:
yield root.parent.value
root = root.parent
raise StopIteration
def tree_sum(self):
return sum(list(self))
parent = Tree()
child = Tree(parent=parent, value=8)
child2 = Tree(parent=child,value=10)
I've changed the default parent value to None.
for i in child2:
print(i)
10
8
0 # 0 is here because the parent value is 0 by default.
I have to do an unrolled linked list for one of my classes. I'm new to python, but not to programming, and for some reason I cannot get around this little problem!
I have a class Node that is to be the node object used within the unrolled linked list. The unrolled linked list class performs all the operations on the Node class.
class UnrolledLinkedList(object):
""" INNER NODE CLASS """
class Node(object):
def __init__(self):
self.array = []
self.next_node = None
""" END NODE CLASS """
def __init__(self, max_node_capacity=16):
self.max_node_capacity = max_node_capacity
self.head = Node()
""" OTHER FUNCTIONS OF UNROLLEDLINKEDLIST CLASS """
The problem comes at the last line of the UnrolledLinkedList class' init function: "global name Node is not defined". I double checked my indentation and looked all over the internet for examples of something like this, but couldn't find any. Would someone mind explaining to me what's wrong?
Methods do not include their class as a scope to be searched. If you want this to work then you will need to use either UnrolledLinkedList.Node or self.Node instead.
The inner class Node is a member of the class UnrolledLinkedList and can only be accessed via self.
def __init__(self, max_node_capacity=16):
self.max_node_capacity = max_node_capacity
self.head = self.Node()
Use:
self.head = self.Node()
and it works.
A class does not create its own name space. Using self.Node(), Python first searches all attributes of the instances. Since it does not find the name Node there, it it searches the class UnrolledLinkedList for Node.
Alternatively, you can use the class name directly:
UnrolledLinkedList.Node()
You can achieve the same without nesting the class Node:
class Node(object):
def __init__(self):
self.array = []
self.next_node = None
class UnrolledLinkedList(object):
def __init__(self, max_node_capacity=16):
self.max_node_capacity = max_node_capacity
self.head = Node()
Qualify Node() with self:
class UnrolledLinkedList(object):
class Node(object):
def __init__(self):
self.array = []
self.next_node = None
def __init__(self, max_node_capacity=16):
self.max_node_capacity = max_node_capacity
self.head = self.Node()
Python needs to qualify references to things. In this case, you could either say UnrolledLinkedList.Node() or self.Node().
There is a class as following:
class N:
def __init__(self, node_id):
self.id = node_id # id (as an integer for example)
self.super = 0
self.color = 0
It is about creating a node. As you can see, there is an attribute, super. I want to call the color of the supernode.
I tried to implement:
node.color = node.super.color
but, it was wrong implementation. Do you have any idea how to get the information of other node?
You need to explicitly pass the parent node -or at least its color, to the class init function
- there is no way a simplist node class can "guess" how it is connected with other node objects.
One way to go is:
class N(object):
def __init__(self, node_id, parent_node):
self.id = node_ide
self.parent = parent_node
self.color = 0
# and you canget parentnode color with self.node.color