0

I was working on 109. Convert Sorted List to Binary Search Tree on leetcode, and I came across a solution that I mostly understand, aside from the use of self.

The solution:

class Solution:
    def sortedListToBST(self, head):
        length = 0
        curr = head
        while curr:
            curr = curr.next
            length += 1

        self.head = head

        def recursion(start, end):
            if start > end: return None
            middle = (start + end) // 2
            # left
            left = recursion(start, middle - 1)

            # root
            root = TreeNode(self.head.val)
            self.head = self.head.next
            root.left = left

            # right
            root.right = recursion(middle + 1, end)
            return root

        return recursion(0, length - 1)

I get confused on the use of self.head = head. I understand self is used to indicate or specify the current instance of a class, and is used to access variables of said class. My current understanding of how this is working is that self.head is being defined as a global variable (outside the scope of recursion(start,end)) that points to the object head. I don't understand why self needs to be used, and why we can't just say something like copyOfHead = head instead of self.copyOfHead = head. I'm sure I'm getting some things wrong here - can somebody help me better understand the what and why of using self. in this instance?

3
  • 1
    The recursion function is referencing the same self that its parent method declares as a parameter, i.e. it's an up-level reference. It refers to the class instance that was used to call sortedListToBST. It's not global. Commented Sep 13, 2022 at 1:32
  • but I think you're right that in this case, referencing self is not providing any benefit here, unless solution.head is referenced outside this function. Commented Sep 13, 2022 at 1:43
  • The only reason to use self.head over some_other_head is if the value is accessed from another method, or if the user of the object somehow needs access to the value of self.head as some_object.head. If neither is the case, you're right, there's no point. Another possibility is that the author wasn't aware of nonlocal and decided on abusing self. as the next best thing. Commented Sep 13, 2022 at 2:27

1 Answer 1

0

It's just providing a global variable so that recursion (which will be called many times) can use it to store state between calls.

Leetcode is designed so that you have to use the class wrapper, but for this algorithm you could have easily written:

self_head = None

def sortedListToBST(head):
    length = 0
    curr = head
    while curr:
        curr = curr.next
        length += 1

    self_head = head

    return recursion(0, length - 1)

def recursion(start, end):
    if start > end: return None
    middle = (start + end) // 2
    # left
    left = recursion(start, middle - 1)

    # root
    root = TreeNode(self_head.val)
    self_head = self_head.next
    root.left = left

    # right
    root.right = recursion(middle + 1, end)
    return root

# Run the function
sortedListToBST(some_input)

Which I think makes it clear that the object-oriented stuff doesn't matter, it's more about being a global variable. However, in your example, recursion is inside sortedListToBST, so I think it could have actually accessed head already. So I think using self was unnecessary and the author didn't realize it. In functional programming terms self.head allows recursion to have side-effects.

You could also eliminate the need for this global variable by just passing head in the arguments of recursion.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.