jacobssohn
jacobssohn

Reputation: 5

Why creating an instance of a class within a class method changes the 'self' argument?

I'm writing a linked list in Python and I've come across an issue which is really troublesome and terrible for debugging and I feel like I'm missing something about Python. I'm supposed to create a singly linked list with some basic functionalities. One of them is the take() function, which is meant to create a new list of n first elements of the original list. However, creating a new instance of the LinkedList class seems to change the .self parameter and the variable node is modified, as the attribute .next is turned to None. In result, when creating a list and then trying to make a new one out of the n elements of it, the program runs indefinitely, but no matter which part I look at, I cannot find the loop or the reason behind it.

class LinkedList:
    def __init__(self, head=None):
        self.head = head


    def is_empty(self):
        if self.head == None:
            return True
        else:
            return False

    def add_last(self, node):
        if self.is_empty():
            self.head = node
            return
        nextEl = self.head
        while True:
            if nextEl.next is None:
                nextEl.next = node
                return
            nextEl = nextEl.next


    def take(self, n):
        node = self.head
        newHead = self.head
        newHead.next = None
        newList = LinkedList(newHead)
        count = 0
        while count < n:
            newList.add_last(node.next)
            node = node.next
            count += 1
        return newList

class Node:
    def __init__(self, data, next=None):
        self.data = data
        self.next = next

Thank you for all your help.

Upvotes: 0

Views: 48

Answers (1)

bb1
bb1

Reputation: 7873

In the take() function the line

newHead.next = None

modifies a node of the linked list, breaking this list. You can fix this as follows:

def take(self, n):
    node = self.head
    newHead = Node(self.head.data)
    newList = LinkedList(newHead)
    count = 0
    while count < n:
        newList.add_last(node.next)
        node = node.next
        count += 1
    return newList

This, however, still will not work correctly since there is a problem with the add_last() function too. This function, I think, is supposed to add a node as the last element of a linked list, but since you do not modify the next attribute of the node, you actually append a whole linked list starting with that node. This can be fixed in the following way:

def add_last(self, node):
    if self.is_empty():
        self.head = node
        return
    nextEl = self.head
    while True:
        if nextEl.next is None:
            nextEl.next = Node(node.data)     
            return
        nextEl = nextEl.next

There are more issues. For example, take(sefl, n) will actually create a list of n+1 elements and will throw an exception if it is applied to a linked list that does not have that many elements.

Upvotes: 1

Related Questions