1. Introduction
# Definition for singly-linked list. # class ListNode: # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution: def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]: dummy = ListNode() p = dummy while list1 != None and list2 != None: if list1.val < list2.val: p.next = list1 list1 = list1.next p = p.next elif list2.val <= list1.val: p.next = list2 list2 = list2.next p = p.next if list1 != None: p.next = list1 if list2 != None: p.next = list2 return dummy.next
Today, I'm brushing a leetcode. It's easy to solve it quickly with a double pointer and a trick of dummy node. But when I finished, I suddenly thought about whether the list1 and list2 in the function would be changed by my various. next operations. Quickly check how python functions pass values and references
2. Understand concepts
In the process of passl by value, the formal parameters of the called function are treated as local variables of the called function, that is, memory space is opened up in the stack to store the values of the arguments put in by the main calling function, thus becoming a copy of the arguments. The characteristic of value transfer is that any operation of the called function on the formal parameters is carried out as a local variable and will not affect the value of the argument variable of the main calling function.
In the pass by reference process, although the formal parameters of the called function also open up memory space in the stack as local variables, the address of the argument variable put in by the calling function is stored at this time. Any operation of the called function on the formal parameter is treated as indirect addressing, that is, the actual parameter variable in the calling function is accessed through the address stored in the stack. Because of this, any operation of the called function on the formal parameter affects the argument variable in the main calling function.
In fact, the difference is that when the value transfer is equivalent to the exam, the school bully outside the field sees your question, then prints the same one, helps you finish it, and then sends you the answer.
Quoting and passing is equivalent to Xueba knowing where you are sitting in the examination room, and then directly taking the test for you.
3. Use in Python
All data stored in Python programs are objects, and each object has an identity, a type and a value.
Depending on the actual function of the variable, when you execute the line a = 8, you will create an object with a value of 8 and a type of int.
The variable name is a reference to this "an int object with a value of 8".
- You can obtain the identity of the object through id()
The parameter of this built-in function is the variable name a, and the value returned by this function is the memory address of the "int object with value 8" referenced by the variable a.
a = 8 print(id(a), id(8)) # 140711661084640 140711661084640
- You can get the data type of a reference object through type()
type(a) # int
- When a variable appears in an expression, it is replaced by the value of the object it references.
- Whether Python functions pass parameters by value or reference?
Passing value and reference are concepts in c/c + +. Everything in Python is an object, and the reference value of the object is passed from the actual parameter to the formal parameter. Just like Python assignment.
If the function receives a reference to a variable object (such as a dictionary or list), it can modify the original value of the object - equivalent to passing the object through "pass reference". If a function receives a reference to an immutable object (such as a number, character, or tuple), it cannot directly modify the original object -- it is equivalent to passing the object by "passing a value".
for instance
- Value transmission
def test(c): print('test before + :', id(c)) c += 2 print('test after + :', id(c)) return c if __name__ == '__main__': a = 2 print('main before invoke test:', id(a)) a_return = test(a) print('main after invoke test: ',id(a)) print('return id:', id(a_return)) # main before invoke test: 140711661084448 # test before + : 140711661084448 # test after + : 140711661084512 # main after invoke test: 140711661084448 # return id: 140711661084512
- Pass reference
In the following example, C is not modified, but c[0] is actually c.get(0). At this time, the modification of c[0] will be directly modified in memory
def test(c): print('test before + :', id(c),id(c[0])) c[0] += 10 print('test after + :', id(c),id(c[0])) return c if __name__ == '__main__': a = [0,0,0] print('main before invoke test:', id(a),id(a[0])) a_return = test(a) print('main after invoke test: ',id(a),id(a[0])) print('return id:', id(a_return),id(a_return[0])) # main before invoke test: 1911175809216 140711661084384 # test before + : 1911175809216 140711661084384 # test after + : 1911175809216 140711661084704 # main after invoke test: 1911175809216 140711661084704 # return id: 1911175809216 140711661084704
If we try to modify c directly, we find that it is the same as the value transfer. The c on the left in c+=2 above and c = c+[1] here are references to another id, which is equivalent to opening up a new memory. Therefore, some people always say that c = c+[1] is very slow
def test(c): print('test before + :', id(c),id(c[0])) c[0] += 10 c = c+[1] #be careful print('test after + :', id(c),id(c[0])) return c if __name__ == '__main__': a = [0,0,0] print('main before invoke test:', id(a),id(a[0])) a_return = test(a) print('main after invoke test: ',id(a),id(a[0])) print('return id:', id(a_return),id(a_return[0])) # main before invoke test: 1911209370432 140711661084384 # test before + : 1911209370432 140711661084384 # test after + : 1911209103488 140711661084704 #be careful # main after invoke test: 1911209370432 140711661084704 # return id: 1911209103488 140711661084704 #be careful
Of course, we usually don't use c = c+[1], we usually use c+=[1], or c.append(1). What happens? It's found that it's equivalent to modifying the original c without using the new c, so some people say it's faster
def test(c): print('test before + :', id(c),id(c[0])) c[0] += 10 c+=[1] print('test after + :', id(c),id(c[0])) return c if __name__ == '__main__': a = [0,0,0] print('main before invoke test:', id(a),id(a[0])) a_return = test(a) print('main after invoke test: ',id(a),id(a[0])) print('return id:', id(a_return),id(a_return[0])) # main before invoke test: 1911209010432 140711661084384 # test before + : 1911209010432 140711661084384 # test after + : 1911209010432 140711661084704 # main after invoke test: 1911209010432 140711661084704 # return id: 1911209010432 140711661084704
As for the examples in the introduction, LIST1 and list2 are equivalent to passing values, which is similar to copying a copy and then processing the copy (the second code of passing references or the code of passing values). However, if list1.val is modified, when the function jumps out, the modification still exists, which is equivalent to passing references (the first code of passing references).
This paper draws lessons from
https://www.cnblogs.com/loleina/p/5276918.html
https://zhuanlan.zhihu.com/p/32828289