Is it a good idea to have functions whose sole purpose it is to call another function? [closed] - python

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 11 months ago.
Improve this question
I wrote code for a Tree traversal. In the Binary_tree class, I wrote three methods: __Inorder, __Postorder, and __Preorder, for tree traversal; and I wrote three other methods to call them and pass in self.root as a parameter so that I don't have to pass it manually every time I want to traverse.
Code:
class Node():
def __init__(self, data):
self.data = data
self.left = None
self.right = None
class Binary_Tree():
def __init__(self):
self.root = None
def insert(self, data):
new_node = Node(data)
if self.root == None:
self.root = new_node
else:
current_node = self.root
while True:
if data > current_node.data:
if not current_node.right:
current_node.right = new_node
return
else:
current_node = current_node.right
else:
if not current_node.left:
current_node.left = new_node
return
else:
current_node = current_node.left
def inorder_traversal(self):
return self.__Inorder(self.root)
def postorder_traversal(self):
return self.__Postorder(self.root)
def preorder_traversal(self):
return self.__Preorder(self.root)
def __Inorder(self, current_node, visited_node = None):
if visited_node is None:
visited_node = []
if current_node:
self.__Inorder(current_node.left, visited_node)
visited_node.append(current_node.data)
self.__Inorder(current_node.right, visited_node)
return visited_node
def __Postorder(self, current_node, visited_node = None):
if visited_node is None:
visited_node = []
if current_node:
self.__Postorder(current_node.left, visited_node)
self.__Postorder(current_node.right, visited_node)
visited_node.append(current_node.data)
return visited_node
def __Preorder(self, current_node, visited_node = None):
if visited_node is None:
visited_node = []
if current_node:
visited_node.append(current_node.data)
self.__Preorder(current_node.left, visited_node)
self.__Preorder(current_node.right, visited_node)
return visited_node
I showed this code to a guy I know and he said "there is no point in writing a function whose sole instruction is to call another function" and it is bad code writing. So, is it true? If yes, then how should I do it?

Your friend is wrong.
Your function (like inorder_traversal) is not just calling another function: it also disallows the caller to pass any arguments, which are none of their business (current_node, visited_node). And this makes it a good decision to have a clean public method, while the underscored "private" functions deal with implementation details that are reflected in their function parameters.
Not your question, but I do see some room for avoiding code repetition, as your base functions have very similar code. Also you could consider creating generators for them instead of populating lists. You could also consider moving those private methods to the Node class.
For example:
class Node():
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def traverse(self, order=0):
if order == -1:
yield self.data
if self.left:
yield from self.left.traverse(order)
if order == 0:
yield self.data
if self.right:
yield from self.right.traverse(order)
if order == 1:
yield self.data
class Binary_Tree():
def __init__(self):
self.root = None
def insert(self, data):
new_node = Node(data)
if self.root == None:
self.root = new_node
else:
current_node = self.root
while True:
if data > current_node.data:
if not current_node.right:
current_node.right = new_node
return
else:
current_node = current_node.right
else:
if not current_node.left:
current_node.left = new_node
return
else:
current_node = current_node.left
def preorder_traversal(self):
if self.root:
return self.root.traverse(-1)
def inorder_traversal(self):
if self.root:
return self.root.traverse(0)
def postorder_traversal(self):
if self.root:
return self.root.traverse(1)
# Demo run
tree = Binary_Tree()
for data in (4,2,3,1,6,5,7):
tree.insert(data)
print(*tree.inorder_traversal())

Related

Doubly Linked list with iterator [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 11 months ago.
Improve this question
I'm trying to implement the doubly-linked list in these singly-linked list operations, but how do I properly implement the previous Node (antNode) in the functions addNode and elimNode?
Almost everything that is done in insNode is applicable in addNode function.
class ListNode:
def __init__(self, data, nextNode=None):
self.data = data
self.nextNode = nextNode
self.antNode = None
class DoublyLinkedListIterator:
def __init__(self, firstNode=None):
self.firstNode = firstNode
self.lastNode = firstNode
self.iterator = firstNode
if firstNode:
self.size = 1
else:
self.size = 0
def addNode(self, data): # Add a Node after the iterator.
"""Pre condition: Iterator defined
Pos condition: The data is inserted into a node after the
iterator. The iterator stands over this node.
"""
newNode = ListNode(data,None) # treats the empty list
newNode.nextNode = None
newNode.antNode = None
if(self.size == 0): # treats the empty list
self.iterator = newNode
self.firstNode = newNode
self.lastNode = newNode
elif self.iterator == self.lastNode:
self.lastNode.nextNode = newNode
self.iterator = newNode
self.lastNode = newNode
else:
newNode.nextNode = self.iterator.nextNode
self.iterator.nextNode = newNode
self.iterator = newNode
self.size += 1
return True
def elimNode(self): # Eliminates the element over the iterator and
# advances the iterator to the next node.
if(self.iterator == self.firstNode):
if(self.lastNode == self.firstNode):
self.lastNode = None
self.firstNode = None
self.iterator = None
else: # more than one node
#self.firstNode = self.firstNode.nextNode
self.firstNode = self.firstNode.nextNode
self.iterator.nextNode = None
self.iterator = self.firstNode
else: # iterator can be under the last or an inner element
currentNode = self.firstNode
while currentNode.nextNode != self.iterator:
currentNode = currentNode.nextNode
if self.iterator == self.lastNode:
self.lastNode = currentNode
self.iterator.nextNode = None
self.iterator = None
currentNode.nextNode = None
else:
currentNode.nextNode = self.iterator.nextNode
currentNode = self.iterator
self.iterator = self.iterator.nextNode
currentNode.nextNode = None
self.size = self.size - 1
return True
The function insNode that inserts a node before the iterator is like this with doubly linked list:
def insNode(self, data): # insert a node before the iterator
"""Pre condition: Iterator defined
Pos condition: The data is inserted into a node before the iterator.
The iterator stands over this node.
"""
newNode = ListNode(data, None) # treats the empty list
newNode.nextNode = None
newNode.antNode = None
if (self.size == 0): # treats the empty list
self.iterator = newNode
self.firstNode = newNode
self.lastNode = newNode
elif self.iterator == self.firstNode: # iterator is on the first element
newNode.nextNode = self.firstNode
self.iterator.antNode = newNode
self.firstNode = newNode
self.iterator = newNode
else: # iterator is on an inner element
newNode.antNode = self.iterator.antNode
self.iterator.antNode.nextNode = newNode
self.iterator.antNode = newNode
self.iterator = newNode
self.size += 1
return True
The answer is: yes you should do similar changes in insNode. However, much of the code is alike, so I would create a helper function to perform the actions these two methods have in common. Also, let the ListNode constructor take an optional argument also for the antNode attribute.
Not your question, but:
The elimNode method should better check that self.iterator is not None.
I find the name iterator confusing, since iterator is a very specific concept in Python, and it is not this. So I would rename that to cursor or currentNode or something. I can understand that this was given in some template code, or exercise, but then it doesn't really speak in favour of the quality of that teaching material.
I don't really see the purpose for the optional node parameter in the constructor of the main class. I would either omit it, or else let it accept a variable number of data values. That would be more practical.
Here is how it could look:
class ListNode:
def __init__(self, data, antNode=None, nextNode=None):
self.data = data
self.nextNode = nextNode
self.antNode = antNode
class DoublyLinkedListWithCursor:
def __init__(self):
self.firstNode = self.lastNode = self.currentNode = None
self.size = 0
def _insertBetween(self, data, before, after):
# Helper function for common logic in insNode and addNode methods
self.currentNode = ListNode(data, before, after)
if after:
after.antNode = self.currentNode
else:
self.lastNode = self.currentNode
if before:
before.nextNode = self.currentNode
else:
self.firstNode = self.currentNode
self.size += 1
def insNode(self, data):
self._insertBetween(data, self.currentNode.antNode if self.currentNode else self.lastNode, self.currentNode)
def addNode(self, data):
self._insertBetween(data, self.currentNode, self.currentNode.nextNode if self.currentNode else self.firstNode)
def elimNode(self):
if not self.currentNode: # Sanity check
return False
if self.currentNode.antNode:
self.currentNode.antNode.nextNode = self.currentNode.nextNode
else:
self.firstNode = self.currentNode.nextNode
if self.currentNode.nextNode:
self.currentNode.nextNode.antNode = self.currentNode.antNode
else:
self.lastNode = self.currentNode.antNode
self.currentNode = self.currentNode.nextNode
self.size -= 1
return True

binary search tree missing 1 required positional argument:

Trying to construct the Binary search tree here
class Node:
# Constructor to create a new node
def __init__(self, data):
self.data = data
self.left = None
self.right = None
class BSTree():
def __init__(self, rootdata):
self.root = Node(rootdata)
def insert(self, data, cur_node):
if data < cur_node.data:
if cur_node.left == None:
cur_node.left = Node(data)
else:
self.insert(data, cur_node.left)
elif data > cur_node.data:
if cur_node.right == None:
cur_node.right = Node(data)
else:
self.insert(data, cur_node.right)
else:
print("Duplicate value!")
def find(self, data, cur_node):
if data < cur_node.data and cur_node.left:
return self.find(data, cur_node.left)
elif data > cur_node.data and cur_node.right:
return self.find(data, cur_node.right)
if data == cur_node.data:
return True
return False
def PreOder(self,root):
if root == None:
pass
else:
print(root.data)
self.PreOrder(root.left)
self.PreOrder(root.right)
a = BSTree()
a.insert(3)
a.insert(4)
a.insert(7)
a.insert(34)
a.insert(24)
a.insert(2)
a.insert(49)
print(a.find(3))
print(a.PreOrder(3))
I am getting an error message: init() missing 1 required positional argument: 'rootdata'
How to fix and print the binary search tree?
Also, what I have up there is just the random number I am try to construct the binary tree out from the list I have
mylist = [1,3,2,4,12,14,23,43,23,44,34,43]
Here is a working and properly formatted update of your code. Not sure what it's doing exactly, but it should give you some clues to solve your task. Maybe you could use an IDE like Visual Studio Code or Pycharm to help you out with python specific stuff.
class Node:
# Constructor to create a new node
def __init__(self, data):
self.data = data
self.left = None
self.right = None
class BSTree:
def __init__(self, rootdata):
self.root = Node(rootdata)
def insert(self, data, cur_node):
if data < cur_node.data:
if cur_node.left is None:
cur_node.left = Node(data)
else:
self.insert(data, cur_node.left)
elif data > cur_node.data:
if cur_node.right is None:
cur_node.right = Node(data)
else:
self.insert(data, cur_node.right)
else:
print("Duplicate value!")
def find(self, data, cur_node):
if data < cur_node.data and cur_node.left:
return self.find(data, cur_node.left)
elif data > cur_node.data and cur_node.right:
return self.find(data, cur_node.right)
if data == cur_node.data:
return True
return False
def pre_order(self, root):
if root is None:
pass
else:
print(root.data)
self.pre_order(root.left)
self.pre_order(root.right)
a = BSTree(3)
a.insert(4, a.root)
a.insert(7, a.root)
a.insert(34, a.root)
a.insert(24, a.root)
a.insert(2, a.root)
a.insert(49, a.root)
print(a.find(3, a.root),)
print(a.pre_order(a.root))
Some issues:
Your BSTree constructor does not create an emtpy tree, but a tree with already one node, and so it expects the data for that node as argument. This design is not good, because it does not support the concept of an empty tree. So the constructor should change and just set self.root to None.
insert takes also more arguments than expected: it does so because it uses that argument for implementing recursion. There are many ways to make it work, but I prefer that the recursive call is made in OOP-style, i.e. the recursive insert method should be placed in the Node class, and act on self instead of on an extra argument. The insert method on the BSTree class can then just be a wrapper around that method, where it gets called on the root node.
A similar issue occurs with find. The solution can be the same as for insert.
And again, the issue occurs also with preOrder: it takes a node as argument. Same solution as discussed above. I would also avoid printing in a method. Instead yield the values.
So here is how that would look:
class Node:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def insert(self, data):
if data < self.data:
if not self.left:
self.left = Node(data)
else:
self.left.insert(data)
elif data > self.data:
if not self.right:
self.right = Node(data)
else:
self.right.insert(data)
else:
print("Duplicate value!")
def find(self, data):
if data < self.data and self.left:
return self.left.find(data)
elif data > self.data and self.right:
return self.right.find(data)
return data == self.data
def preOrder(self):
yield self.data
if self.left:
yield from self.left.preOrder()
if self.right:
yield from self.right.preOrder()
class BSTree():
def __init__(self):
self.root = None
def insert(self, data):
if not self.root:
self.root = Node(data)
else:
self.root.insert(data)
def find(self, data):
return self.root.find(data) if self.root else False
def preOrder(self):
if self.root:
yield from self.root.preOrder()
a = BSTree()
a.insert(3)
a.insert(4)
a.insert(7)
a.insert(34)
a.insert(24)
a.insert(2)
a.insert(49)
print(a.find(3))
print(*a.preOrder()) # With * we splash every yielded value as argument to print().

How to get the length of a tree in python binary search

class Node:
def __init__(self,data=None):
self.data=data
self.left_child=None
self.right_child=None
self.parent=None
self.root = None
class BinarySearchTree:
def __init__(self):
self.root=None
def add(self, data):
if self.root == None:
self.root = Node(data)
else:
self.add_helper(data, self.root)
def add_helper(self, data, cur_node):
if data < cur_node.data:
if cur_node.left_child == None:
cur_node.left_child = Node(data)
cur_node.left_child.parent = cur_node # set parent
else:
self.add_helper(data, cur_node.left_child)
elif data > cur_node.data:
if cur_node.right_child == None:
cur_node.right_child = Node(data)
cur_node.right_child.parent = cur_node # set parent
else:
self.add_helper(data, cur_node.right_child)
else:
print("data already in tree!")
def __len__(self):
if self.root is None:
return 0
else:
return (self.__len__(self.left_child) + 1 +self. __len__(self.right_child))
So i am trying to return the length of the binary search tree list, so i tried using the len method for my binary search tree class. However, this is not working correctly. I need it to be able to not take in any parameters, and just return an integer for the length of the binary search tree list. What am i missing and what am i doing wrong here?
You will need a helper function that takes a Node argument. Then do the recursion on the left and right of the node.
def __len__(self):
return self.tree_len(self.root)
def tree_len(self, node):
if node is None:
return 0
else:
return 1 + max(self.tree_len(node.right_child), self.tree_len(node.left_child))

NameError When Implementing Inorder Traversal

I'm trying to implement a Binary Search Tree in Python, and I'm having difficulty in understanding the NameError I get when I call the inorder traveral method on my tree. I have already created a BST instance, and I've defined the in_order_traversal() method before I call it on the instance, so why am I getting a NameError?
class BSTNode:
def __init__(self,data):
self.data = data
self.left = None
self.right = None
class BST:
def __init__(self):
self.root = None
def insert(self,data):
new_node = BSTNode(data)
if self.root == None:
self.root = new_node
else:
ptr = self.root
prev = None
while ptr != None:
prev = ptr
if data <= ptr.data:
ptr = ptr.left
else:
ptr = ptr.right
if data <= prev.data:
prev.left = new_node
else:
prev.right = new_node
def in_order_traversal(self):
if self.root != None:
in_order_traversal(self.root.left)
print(root.data)
in_order_traversal(self.root.right)
bst = BST()
bst.insert(50)
bst.insert(25)
bst.insert(100)
bst.insert(80)
bst.insert(30)
bst.in_order_traversal()
You forgot the self.
def in_order_traversal(self):
if self.root != None:
self.in_order_traversal(self.root.left)
print(root.data)
self.in_order_traversal(self.root.right)

How to call a class method using an instance of a different class in Python?

I am a trying to implement a binary tree using two classes - Node and Binary Tree. When I am inserting the nodes (left or right), I am using the methods insert_left_node and insert_right_node which are class BinaryTree's methods, but I am also using class Node to create a node. After every node insertion, the current object is returned.
Now, how do I call class BinaryTree's insertion methods using the returned object - current. E.g. In the second last line of the code, statement n3 = n1.insert_left_node(33) fails with AttributeError: 'Node' object has no attribute 'insert_left_node'
I need an alternative way to achieve this.
Code:
class Node(object):
def __init__(self, data):
self.data = data
self.left = None
self.right = None
class BinaryTree(object):
def __init__(self, root=None):
self.root = Node(root)
def insert_left_node(self, data):
if not self.root:
self.root = Node(data)
else:
current = self.root
while True:
if current.left:
current = current.left
else:
current.left = Node(data)
break
return current
def insert_right_node(self, data):
if not self.root:
self.root = Node(data)
else:
current = self.root
while True:
if current.right:
current = current.right
else:
current.right = Node(data)
break
return current
if __name__ == '__main__':
r = BinaryTree(34) # root
n1 = r.insert_left_node(22)
n2 = r.insert_right_node(45)
n3 = n1.insert_left_node(33) # Fails
print n3
Your request literally doesn't make any sense. To achieve what you want you should just add the needed methods to the class you want to use. Try something similar to the following:
class Node(object):
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def insert_left_node(self, data):
self.left = Node(data)
def insert_right_node(self, data):
self.right = Node(data)

Categories