Hawkeye312
Hawkeye312

Reputation: 61

Class method not finding the argument given

I just learned how to create Binary Search Trees in C#. I decided to try to code the same thing in Python 3.x. However, when I got to my Print method, this error showed up:

Traceback (most recent call last):
  File "C:\Users\danie\Desktop\Python\BinarySearchTree\BinarySearchTree\BinarySearchTree.py", line 62, in <module>
    b.BSTprint()
  File "C:\Users\danie\Desktop\Python\BinarySearchTree\BinarySearchTree\BinarySearchTree.py", line 46, in BSTprint
    BST.Print(current)
TypeError: Print() missing 1 required positional argument: 'cur'

The problem, I did put in the required positional argument. I tried fixing it myself and found that if I remove the self parameter, it works. However, I always thought you needed to have that self parameter in all of the class methods. I have no idea what is wrong. Here is the code

import random
class BST:
    #Node class 
    class Node:
        data = None
        left = None
        right = None
        def __init__(self, d):
            self.data = d
    first = None
    #Add method
    def Add(self, d):
        #Checks if the Binary Search Tree is empty
       if(BST.first == None):
           BST.first = BST.Node(d)
           #Debugging purposes
           #print("Added: {}".format(d))
           return;
       else:
           newNode = BST.Node(d)
           cur = BST.first
           while(cur != None):
               if(cur.data < newNode.data):
                   if(cur.left == None):
                       cur.left = newNode
                       #print("Added: {}".format(newNode.data))
                       return
                   else:
                       cur = cur.left
               elif(cur.data > newNode.data):
                   if(cur.right == None):
                       cur.right = newNode
                       #print("Added: {}".format(newNode.data))
                       return
                   else:
                       cur = cur.right
               else:
                    print("Value already in BST")
                    return


    def BSTprint(self):
        current = BST.first
        if(current == None):
            return
        BST.Print(current)
    def Print(self, cur):

        if(cur.left != None):
            BST.Print(cur.left)
        print(cur.data)
        if(cur.right != None):
            BST.Print(cur.right)



b = BST()
#Adds values into BST
for i in range(10):
    x = random.randint(1,100)
    b.Add(x)
b.BSTprint()

Upvotes: 1

Views: 137

Answers (3)

PM 2Ring
PM 2Ring

Reputation: 55469

As others have noted, in the Print method you need to call BSTprint as an instance method, eg self.BSTprint(node) so that the instance gets passed to the method correctly. But there are a few other issues with your code.

Doing first = None creates first as a class attribute, which means it would be shared by all BST instances. That's not a good idea: each instance should have its own root node! Of course, if the program only creates a single BST instance you wouldn't notice that bug, but if you decide that you want to create several trees then Bad Things would happen. ;)

Instead, you should creates first as an instance attribute, the usual way to do that is in the __init__ method.

Your code defines the Node class inside the BST class. It's fine to do that, but it's a little unusual in Python. It's simpler just to make it a separate class. Once again, you're defining the Node attributes as class attributes. That's actually ok here, since you never modify those class attributes: your Add method creates instance attributes with the same names that "shadow" the class attributes. However, it makes the code a little simpler to analyse if you get rid of those class attributes and simply use instance attributes from the outset.

Here's a modified version of your code. I made a few cosmetic changes so that the code conforms with the Python PEP-0008 style guide. Simple variable, attribute, and method names should begin with lower case letters. I also got rid of redundant parentheses. And it's recommended to use is when testing for the None singleton, it's a little more efficient (and nicer to read) than using == or != value testing.

I changed first to root, in line with Berk Özbalcı's remark. And I gave Node a __repr__ method to make it easier to print the Node data.

I also added a call to random.seed, with a hard-coded seed value so that the program generates the same numbers each time we run it. That makes testing and debugging much easier. It can be hard to figure out what's going wrong when the data keeps changing.

import random

random.seed(42)

class Node:
    """ A binary tree node """
    def __init__(self, d):
        self.data = d
        self.left = self.right = None

    def __repr__(self):
        return repr(self.data)

class BST:
    """ Binary search tree """
    def __init__(self):
        self.root = None

    def add(self, d):
       # Check if the Binary Search Tree is empty
       if self.root is None:
           self.root = Node(d)
           #Debugging purposes
           print("Added: {} root".format(self.root))
           return
       else:
           newNode = Node(d)
           cur = self.root
           while cur is not None:
               if cur.data < newNode.data:
                   if cur.left is None:
                       cur.left = newNode
                       print("Added: {} left".format(newNode))
                       return
                   else:
                       cur = cur.left
               elif cur.data > newNode.data:
                   if cur.right is None:
                       cur.right = newNode
                       print("Added: {} right".format(newNode))
                       return
                   else:
                       cur = cur.right
               else:
                    print("Value already in BST:", d)
                    return

    def bst_print(self):
        current = self.root
        if current is None:
            return
        self.show(current)

    def show(self, cur=None):
        if cur.left is not None:
            self.show(cur.left)
        print(cur)
        if cur.right is not None:
            self.show(cur.right)


b = BST()

# Add values into BST
for i in range(10):
    x = random.randint(1, 100)
    print(x)
    b.add(x)

print('\nSorted')
b.bst_print()

output

82
Added: 82 root
15
Added: 15 right
4
Added: 4 right
95
Added: 95 left
36
Added: 36 left
32
Added: 32 right
29
Added: 29 right
18
Added: 18 right
95
Value already in BST: 95
14
Added: 14 left

Sorted
95
82
36
32
29
18
15
14
4

Upvotes: 0

pramesh
pramesh

Reputation: 1954

Things I would like to highlight:

BST is a class

Print is a object method(bound to object and not class) and it requires the object reference to be passed(self) which is different from other languages Java/C++.

You're calling BST.Print which is similar to calling static methods in Java/C++, but its wrong because Print method takes object parameter

Since you're calling a method that is object bound(since it takes self parameter), you need to call it with objects.

The point is:

If you're using methods with self parameter then they should be called with objects. If you want to call them from class then you can use @staticmethod and remove the self parameter and pass the object you want to process

Please refer: Difference between Class and Instance methods

Hope this helps

Upvotes: 1

Berk &#214;zbalcı
Berk &#214;zbalcı

Reputation: 3196

You've got class variables and instance variables mixed up.

In Python, the first argument of methods are reserved for the calling object (except in some cases they aren't, such as in classmethods or staticmethods). Modify the Add method like this:

class BST:
...
    def Add(self, d):
        if self.first is None:
            self.first = BST.Node(d)
            return
    ...

Note that BST.Node(d) is still the same, because I'm referring to something that is belonging to the class: another class.

Modify BST.Print(current) to self.Print(current).

It's uncommon to refer to the root node of a BST as first, prefer root instead!

Upvotes: 1

Related Questions