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.
Related
I'm trying to design a Queue data structure with python 3.6
The queue has the aim to keep track node objects with these attributes:
class node(object):
def __init__(self, state, parent):
self.state = state
self.parent = parent
I want avoid to incorporate nodes with the same state in the queue. So I design the following queue:
class queue(object):
def __init__(self):
self.list = []
self.explored = set()
def insert(self, element):
self.list = [element] + self.list
self.explored.add(str(element.state))
return self.list
def pop(self):
oldest_element = self.list.pop()
self.explored.remove(str(oldest_element.state))
return oldest_element
def empty(self):
return len(self.list) == 0
def check_member(self, other):
return other in self.explored
In order to check if a state of a node is in the queue, I use the check_member method with the attribute state as a string type to see if is contained in the set with all the string state of the members. But this is still slowly.
So it is possible to check if an instance has the same attribute of another instance that could differ in other attributes? For example, two nodes, same state attributes but different parents attributes.
How can keep the order of the elements and still checking if some element is in the queue in O(1) without using the additional explored set?
You need a set/dict type object to achieve O(1) contains-check complexity. The easiest would be to use an OrderedDict as your underlying data container. Use state as key and the node as the value. That way, the states are enforced to be unique, and the order is maintained nonetheless:
from collections import OrderedDict
class queue(object):
def __init__(self):
self.q = OrderedDict()
def insert(self, element):
s = str(element.state)
if s not in self.q:
self.q[s] = element # adds to the end
def pop(self):
return self.q.popitem(0)[1] # returns the node from beginning
def empty(self):
return not self.q
def check_member(self, element):
return str(element.state) in self.q
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've written up a class as seen below. I want to add the attribute of 'parent' to my base class Node. I was wondering if someone could show me how to properly do this. I've been given guidance on how to do it but I'm not entire sure how to write it syntax wise. Here is the suggested way to do it...
generally I would hide the parent attribute behind a property so when
its set, the children array of the previous parent can be modified so
if you say n.parent = x, it actually remove node n from it's parent
and set the parent value
class Node(object):
def __init__(self, name, attributes, children):
self.name = name
self.attributes = attributes if attributes is not None else {}
self.children = children if children is not None else []
class Camera(Node):
def __init__(self, name="", attributes=None, children=None, enabled=True):
super(Camera, self).__init__(name=name, attributes=attributes, children=children)
self.enabled = enabled
updated
import weakref
class Node(object):
_parent = None
def __init__(self, name, attributes, children, parent):
self.name = name
self.attributes = attributes if attributes is not None else {}
self.children = children if children is not None else []
self.parent = parent
for child in children:
child.parent = self
#property
def parent(self):
return self._parent() if self._parent is not None else None
#parent.setter
def parent(self, newparent):
oldparent = self.parent
if newparent is oldparent:
return
if oldparent is not None:
oldparent.children.remove(self)
if self not in newparent.children:
newparent.children.append(self)
self._parent = weakref.ref(newparent) if newparent is not None else None
class Camera(Node):
def __init__(self, name="", attributes=None, children=None, enabled=True, parent=None):
super(Camera, self).__init__(name=name, attributes=attributes, children=children, parent=parent)
self.enabled = enabled
Camera()
Example code, incorporating weakref to avoid reference cycles that can delay cleanup (or prevent it entirely in some cases, particularly on Python 3.3 and earlier):
import weakref
class Node:
# If this is Python 2, you need to explicitly inherit from object to
# be a new-style class with descriptor support (which allows properties), so
# the class line would be:
# class Node(object):
# On Py3, it's implicit and can be omitted
# Ensure attribute readable so getter/setter don't need to use has/getattr
# Will be allocated per-instance when self.parent is assigned in __init__
# So on Py3.3+, it will still get the compact key-sharing dicts for attributes
_parent = None
# Adding defaults for all values matching Camera for simplicity
def __init__(self, name='', attributes=None, children=None, parent=None):
self.name = name
self.attributes = attributes if attributes is not None else {}
self.children = children if children is not None else []
self.parent = parent
for child in children:
child.parent = self
#property
def parent(self):
return self._parent() if self._parent is not None else None
#parent.setter
def parent(self, newparent):
oldparent = self.parent
# If setting to existing parent, then no-op
# Remove this check and early-out if you want to be able to move
# a node to the end of its parent's children by reassigning the same parent
if newparent is oldparent:
return
if oldparent is not None:
oldparent.children.remove(self)
if self not in newparent.children:
newparent.children.append(self)
self._parent = weakref.ref(newparent) if newparent is not None else None
Typically, to avoid issues with changing parent class prototypes, I put additional parameters to child class __init__ methods first, not last. Because I gave __init__ defaults on Camera, this makes Camera very simple:
class Camera(Node):
def __init__(self, enabled=True, *args, **kwargs):
super().__init__(*args, **kwargs)
# On Py2, super isn't magic, so you need to be explicit unlike Py3:
# super(Camera, self).__init__(*args, **kwargs)
self.enabled = enabled
As you can see, by moving the Camera unique __init__ param to the front, Camera can stop paying attention to changes in the Node __init__; the new Camera works with the original Node or the new Node (that accepts parent and assigns self.parent) just fine, because it's less tightly coupled to the exact parameter ordering. Note that this does mean that if enabled is not passed positionally, then all arguments must be passed by keyword.
Please comment if I made any mistakes, but that should be close to correct. In general, I had the Node class use the parent accessor to simplify the code by removing the difficulty with handling None properly (None is not weak referencable).
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
# ...
I'm trying to make a tree that has a recursive 'printAll' method.
My code is:
class Node(object):
def __init__(self, children=[], tag=None):
self.children = children
self.tag = tag
def appendChild(self, child):
self.children.append(child)
def getChildren(self):
return self.children
def printAll(self):
print self.getChildren()
for child in self.children:
child.printAll()
And when I run it I get this: "maximum recursion depth exceeded while calling a Python object".
I'm guessing it has something to do with passing the top level scope down to the child when calling the child's printAll() method, causing an infinite loop. Any help is much appreciated.
Try changing your default children:
class Node(object):
def __init__(self, children=None tag=None):
self.children = children if children is not None else []
self.tag = tag
def appendChild(self, child):
self.children.append(child)
def getChildren(self):
return self.children
def printAll(self):
print self.getChildren()
for child in self.children:
child.printAll()
You might have a case of the "mutable default argument"