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)