vkaul11
vkaul11

Reputation: 4214

Why do we need to put self as the argument while calling another class function

I understand that while defining functions we have to use self as the first argument but in my particular coding example for insert_node method I got an error while calling insert_node(node,new_node) saying 3 arguments expected when I did not use self as the first argument in insert_node

class Node:
    def __init__(self,value=None):
        self.value = value
        self.left = None
        self.right = None
class BST:
    def __init__(self,value=None):
        self.root = Node(value)
    def insert(self,value):
        if self.root == None:
            self.root = Node(value)
            return
        curr = self.root
        new_node = Node(value)
        def insert_node(self,node,new_node):
            if node.value == new_node.value:
                return
            if node.value > new_node.value:
                if node.left is None:
                    node.left = new_node
                    return
                else:
                    insert_node(self,node.left,new_node)
            else:
                if node.right is None:
                    node.right = new_node
                    return
                else:
                    insert_node(self,node.right,new_node)
        insert_node(self,curr,new_node)

Upvotes: 1

Views: 70

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1121266

insert_node() is not a method, it is a function nested inside insert(). You don't need to use self in this function, at all, because it makes no use of that argument, and even if it did, it could access the self reference from the parent insert() method as a closure.

Removing the self argument altogether works:

class BST:
    def __init__(self,value=None):
        self.root = Node(value)

    def insert(self,value):
        if self.root == None:
            self.root = Node(value)
            return
        curr = self.root
        new_node = Node(value)

        def insert_node(node, new_node):
            if node.value == new_node.value:
                return
            if node.value > new_node.value:
                if node.left is None:
                    node.left = new_node
                    return
                else:
                    insert_node(node.left, new_node)
            else:
                if node.right is None:
                    node.right = new_node
                    return
                else:
                    insert_node(node.right, new_node)

        insert_node(curr, new_node)

You can move that function out of the insert() method too, it doesn't need to be nested there:

def insert_node(node, new_node):
    if node.value == new_node.value:
        return
    if node.value > new_node.value:
        if node.left is None:
            node.left = new_node
            return
        else:
            insert_node(node.left, new_node)
    else:
        if node.right is None:
            node.right = new_node
            return
        else:
            insert_node(node.right, new_node)

class BST:
    def __init__(self,value=None):
        self.root = Node(value)

    def insert(self,value):
        if self.root == None:
            self.root = Node(value)
            return
        curr = self.root
        new_node = Node(value)
        insert_node(curr, new_node)

However, this really should be a method on the Node class:

class Node:
    def __init__(self, value=None):
        self.value = value
        self.left = None
        self.right = None

    def insert_node(self, new_node):
        if self.value == new_node.value:
            return
        if self.value > new_node.value:
            if self.left is None:
                self.left = new_node
                return
            else:
                self.left.insert_node(new_node)
        else:
            if self.right is None:
                self.right = new_node
                return
            else:
                self.right.insert_node(new_node)

class BST:
    def __init__(self,value=None):
        self.root = Node(value)

    def insert(self,value):
        if self.root == None:
            self.root = Node(value)
            return
        curr = self.root
        new_node = Node(value)
        curr.insert_node(new_node)

Because you access insert_node() on Node instances (via curr.insert_node(...), self.left.insert_node(...) and self.right.insert_node(...), it is bound to that instance for you by Python, and passed into the method as self.

Upvotes: 4

Related Questions