Home > Blockchain >  Modify a class in a function to reflect change in calling function (Python)
Modify a class in a function to reflect change in calling function (Python)

Time:07-08

I have a class as follows:

class ListNode:
     def __init__(self, val=0, next=None):
         self.val = val
         self.next = next

I create a linked list as:

ll = ListNode(1)
ll.next = ListNode(2)

I want to copy the list to a new list by create new nodes in a function:

def create_new_node(res, l):
            print(l.val)
            res.next = ListNode(l.val)
            l=l.next
            print("Next", l.val)
            res=res.next

res = ListNode()
while ll:
        # Based on some condition
        create_new_node(res, ll)

>>> 1
Next 2
1
Next 2
....

However, this goes into a infinite loop since the ll never progresses to the next node in the while loop outside of the create_node_function even though l (which is a reference of ll) is being made to point to the next node as l=l.next.

Are classes not passed by reference in Python, and can they not be modified in another function to reflect the changes in the calling function?

CodePudding user response:

In python objects are passed by assignment. You can see this with the following code.

test_list = [1,2,3]
test_dict = {1:'a', 2:'b'}
test_tup = (1,2,3)
test_int = 5
test_str = 'hello world'

def change_test(mylist, mydict,myint, mystr):
    print('list: ', id(mylist), 'dict: ', id(mydict),'int: ', id(myint),'str: ', id(mystr))


change_test(test_list, test_dict, test_int, test_str)

print('list: ', id(test_list),'dict: ', id(test_dict),'int: ', id(test_int),'str: ', id(test_str))

the output is:

list:  4346425984 dict:  4347616128 int:  4345676144 str:  4347344688
list:  4346425984 dict:  4347616128 int:  4345676144 str:  4347344688

You see the id's inside and outside the function are the same, so they are the same value. However, when you change a mutable object the id's stays the same and with immutable objects the id changes.

Class instances are mutable so they will act similar to pass by reference. We can see this by checking the id's on each object in the following code.

def create_new_node(res, l):
    print('in func: ', id(l))
    l.val = 99

ll = ListNode(1)
ll.next = ListNode(2)

res = ListNode()
print('out of func: ', id(ll), ll.val)
create_new_node(res, ll)
print('out of func: ', id(ll), ll.val) 

the output is

out of func:  4334042752 1
in func:  4334042752
out of func:  4334042752 99

The problem with your code is the line

l=l.next

when we pass ll into create_new_node l is ll but when we set l to l.next, l is now l.next and not ll, l.next has a different address in memory. To make your code work and copy the list return l like so.

def create_new_node(res, l):
    res.next = ListNode(l.val)
    l=l.next
    res=res.next
    return l

ll = ListNode(1)
ll.next = ListNode(2)

res = ListNode(ll.val)

current = ll
while current:
    current = create_new_node(res, current)
  • Related