I want to create a Tree data structure that consists of TreeNode objects. The root is a TreeNode. Each TreeNode has one parent TreeNode and a list of children TreeNodes.
The Tree is built up recursively. I simplified the code to make the example not too difficult. The function get_list_of_values_from_somewhere works correctly. The recursion ends when there are no child_values for a TreeNode and get_list_of_values_from_somewhere returns an empty list. That works perfectly well.
The children member of each TreeNode is not correct. The script collects all the TreeNodes in a list (node_list). There I can check that each TreeNode has a parent node and this parent node is correct.
But for some reason they all have the same list of childrens. I don't understand why. Everything else is correct. The recursion works, the TreeNodes are created correctly, their parent is correct. Why is their children list not filled correctly and how would you edit the memver variables of the instances after creating the instance?
class Tree(object):
def __init__(self, root_value):
print ("Creating tree")
self.root = self.createTree(root_value)
self.node_list = []
def createTree(self, value, parent=None):
node = TreeNode(value, parent)
children_values = get_list_of_values_from_somewhere()
for child_value in children_values:
child_node = self.createTree(child_value, node)
self.node_list.append(child_node)
node.children.append(child_node)
# I also tried alternatives:
#node.insertChildren(self.createTree(child_value, node))
#node.insertChild(child_node)
return node
class TreeNode(object):
def __init__(self, value, parent=None, children=[]):
self.value = value
self.parent = parent
self.children = children
def insertChildren(self, children=[]):
self.children += children
def insertChild(self, child):
self.children.append(child)
if __name__ == '__main__':
tree = Tree(1)
#tree.node_list contains a list of nodes, their parent is correct
#tree.root.children contains all children
#tree.node_list[x] contains the same children - although many of them should not even have a single child. Otherwise the recursion would not end.
Be very, very cautious of this:
def __init__(self, value, parent=None, children=[]):
and this:
def insertChildren(self, children=[]):
The initial value -- the list object created by [] -- is a single object which is shared. Widely.
You are using this single, shared, default list object widely.
You may want to use this instead.
def __init__( self, value, parent= None, children= None ):
if children is None: children= []
This technique will create a fresh, empty list object. No sharing.
Related
it might be a silly question since I'm new to Python.
However, I hope someone can explain this because I try to find lots of resource but still hardly understand the mechanism behind.
So I create a Parent Class and a Child Class. Parent Class have set_name, get_name method
In Child Class, I defined a new method call Turn_Uppercase which calling get_name then uppercase the name. And when using Turn_Uppercase Method, I have to filled in Child Class Name, otherwise it would not work.
Can someone explain the mechanism here!
Let's me explain in code:
So first I create a Parent Class with get_name and set_name method.
class Parent:
def __init__(self, text_input):
self.__name = ""
self.name = text_input
#property #this is get_name
def name(self):
return self.__name
#name.setter #this is set_name
def name(self, text_input: str):
if isinstance(text_input, str): # check input has to be string
self.__name = text_input
else:
print('Wrong type of data')
Then I create a Child Class with new method called Turn_uppercase
class Child_to_parent(Parent):
def __init__(self):
pass
def turn_uppercase(self):
return self.name.upper()
Now I put in some object and use Turn_uppercase Method, I have to fill in Child Class Name
test1 = Child_to_parent
test1.name = "abcdef" # using parent method
print(f'{test1.turn_uppercase(Child_to_parent)}') # using child method
When using parent method through property name, I don't need to declare Child Class Name, but when it comes to use Turn_uppercase Method then I have to.
Why it works this way?
This line makes all the difference
test1 = Child_to_parent
You are not creating an object here, instead merely assigning a reference to the class itself. What you must be doing is
test1 = Child_to_parent() #>Create the object!
test1.name = "abcdef"
print(f'{test1.turn_uppercase()}')
Now why it works with the class? It's because you attached a attribute to the class called name. The method you called used the class as argument and evaluated the class attribute!
Read this answer for a better understanding!
In python, using constructors and Class I have created nodes. I need to get its parent and their parent nodes. I have got that node, its parent(that has marked when created by a constructor).
I also tried to create a function to print a node and its parents. However how do I pass the parents'parent node so i can get that also.
Given that you didnt show any code its hard to tell what your really trying to do. However assuming your mean nodes like in a tree then below simple example shows how you could recursivly work back up the tree to show the relationships. this of course is not a complete example but should give you an idea.
class node():
def __init__(self, name, parent=None):
self.name = name
self.parent: node = parent
def get_bottom_up_ancestors(self):
if self.parent:
return [self.name] + self.parent.get_bottom_up_ancestors()
return [self.name]
def get_top_down_ancestors(self):
return self.get_bottom_up_ancestors()[::-1]
root = node("Top")
child1 = node("first", parent=root)
child2 = node("second", parent=root)
grandchild1 = node("grandchild", parent=child1)
print(grandchild1.get_bottom_up_ancestors())
print(grandchild1.get_top_down_ancestors())
OUTPUT
['grandchild', 'first', 'Top']
['Top', 'first', 'grandchild']
I don't quite understand what you are talking about but from what I DO understand there is no such thing as a parent object only parent classes so a node parent would not be possible
is it possible to achieve type inheritance without overwriting class methods? Take for example this code:
class Parent:
def special_method(self, name):
print("hello, {}!".format(name))
class Child:
def __init__(self, injected_parent):
self.parent = injected_parent
def special_method(self):
self.parent.special_method("Homer Simpson")
parent = Parent()
child = Child(parent)
child.special_method()
# hello, Homer Simpson!
Works as expected, but I want the type of child to be Parent and not Child:
print(type(child))
<class '__main__.Child'>
One way I've seen it done is to extend Child with:
class Child:
def __init__(self, injected_parent):
self.parent = injected_parent
self.__class__ = Parent
...
However, then child's special_method gets overwritten:
parent = Parent()
child = Child(parent)
child.special_method()
# TypeError: special_method() missing 1 required positional argument: 'name'
Any way to make child have type Parent without side-effects?
It seems like what you want to do is just regular inheritance, but as #juanpa.arrivillaga pointed out, you are using composition instead. What you are trying to do by changing the __class__ and overloading a method will not work. Here is an example using inheritance which will allow you to overload the method while still having access to the original method and to have child be an instance of parent which seems to meet your requirements:
class Parent:
def special_method(self, name):
print("hello, {}!".format(name))
class Child(Parent):
def special_method(self):
super().special_method("Homer Simpson")
child = Child()
Now, child will still have a type of Child, but with classes what you want to be checking instead is whether it is an instance of the superclass using isinstance:
>>> child.special_method()
hello, Homer Simpson!
>>> type(child)
<class '__main__.Child'>
>>> isinstance(child, Parent)
True
I want to know when a tree is similar to part of another, for instance when
When did Beyonce start becoming popular?
is partly included in the following sentences :
She started becoming popular in the late 1990s (1st case)
She rose to fame in the late 1990s (2nd case)
I am able to say when one text is strictly included included in another : I created a class that transforms spaCy array to tree and I show later how to transform text to spaCy.
class WordTree:
'''Tree for spaCy dependency parsing array'''
def __init__(self, tree, is_subtree=False):
"""
Construct a new 'WordTree' object.
:param array: The array contening the dependency
:param parent: The parent of the array if exists
:return: returns nothing
"""
self.parent = []
self.children = []
self.data = tree.label().split('_')[0] # the first element of the tree # We are going to add the synonyms as well.
for subtree in tree:
if type(subtree) == Tree:
# Iterate through the depth of the subtree.
t = WordTree(subtree, True)
t.parent=tree.label().split('_')[0]
elif type(subtree) == str:
surface_form = subtree.split('_')[0]
self.children.append(surface_form)
And I can tell when one sentence is included in another tahnks to the following functions :
def isSubtree(T,S):
if S is None:
return True
if T is None:
return False
if areIdentical(T, S):
return True
return any(isSubtree(c, S) for c in T.children)
def areIdentical(root1, root2):
'''
function to say if two roots are identical
'''
# Base Case
if root1 is None and root2 is None:
return True
if root1 is None or root2 is None:
return False
# Check if the data of both roots their and children are the same
return (root1.data == root2.data and
((areIdentical(child1 , child2))
for child1, child2 in zip(root1.children, root2.children)))
Indeed, for instance :
# first tree creation
text = "start becoming popular"
textSpacy = spacy_nlp(text)
treeText = nltk_spacy_tree(textSpacy)
t = WordTree(treeText[0])
# second tree creation
question = "When did Beyonce start becoming popular?"
questionSpacy = spacy_nlp(question)
treeQuestion = nltk_spacy_tree(questionSpacy)
q = WordTree(treeQuestion[0])
# tree comparison
isSubtree(t,q)
Returns True. Therefore when can I say that a tree is partly included (1st case) in another or similar (2nd case) to another ?
I have what I thought would be a pretty straightforward task, but it has turned into me questioning everything I know about Classes (which to be fair wasn't much to begin with).
I have a parent class and I want to use the attributes of that instance in calculations to be performed in the child class, which is to be created from the init of the parent class. However, I don't seem to be able to reference them from the child class.
I have found some suggestions to init the parent class from the child class, however, that just creates an endless loop in my case.
class User(object):
def __init__(self, a, b):
self.a = a
self.b = b
self.child.append(Child(c=4))
class Child(User)
def __init__(self, c):
self.c = c + User.b
print self.c
From the code and the question, I'm guessing Child really just needs to access some attributes of User, in this example self.b
Inheritance is not the way to go. Inheritance is when you want to reuse a lot of attributes and methods, and re-implement some of them. Like two class "car" and "truck" would both inherits from a class "vehicles"
What you describe with the "Parent-Child" is more like ownership. The class User owns some Child (as attributes), and you want the Child to access data from their owner. What you need to do is to pass a reference of the owner (parent) to the child.
class User(object):
def __init__(self, b):
self.b = b
self.child.append(Child(c=4,parent=self))
class Child(object)
def __init__(self, c, parent):
self.parent=parent
self.c = c + self.parent.b
print(self.c)
Of course in this really simple example, the most obvious way to program it would be to pass b in the child constructor, like this:
class User(object):
def __init__(self, b):
self.b = b
self.child.append(Child(4,b))
class Child(object)
def __init__(self, c, b):
self.c = c + .b
print(self.c)
But for a more complex task, passing a reference to the parent can be better or necessary.