1

When you call 'append' with a list, the pointer of the list is passed in, so the original data is changed.

>>> tmp = [1,2]
>>> tmp.append(3)
>>> tmp
[1, 2, 3]

Here comes my question. For the following code, when I pass the Node object named 'head' into the method 'get', I expect that head would point to the second node with value 2 after calling the method. However, it turns out that 'head' is still pointing to the first node with value 1.

>>> class Node:    
        def __init__(self, val):
            self.val  = val
            self.next = None    
        def get(self, index):
            for i in range(index):
                self = self.next
            return self.val

>>> head = Node(1)
>>> head.next = Node(2)
>>> head.get(1)
2
>>> head.val
1

Can anyone explain why is this happening? To my understanding, as Node is mutable, a reference should be passed in. How can I know whether a reference or value is passed in? Thanks in advance!

Xinming
  • 117
  • 1
  • 6

2 Answers2

1

Just to add on to @blhsing, you're doing local reassignment (nothing to do with call-by-value or reference), and you can verify this with:

a1 = [1]
def expand(a):
    a = a + [2]
    return a
a2 = expand(a1)
print(a1) # prints [1]
print(a2) # prints [1, 2]
iamanigeeit
  • 784
  • 1
  • 6
  • 11
  • Thanks for the comment! It does make sense to me that `expand` won't change the original list, but why can `append` method modify the original list? @blhsing @iamanigeeit – Xinming Sep 10 '18 at 04:07
  • As previous commenters have mentioned, Python is passing a reference to the original list, and since list is mutable, you can modify it. It wouldn't make sense to copy a 1000000-item list every time you want a function to add to it. – iamanigeeit Sep 10 '18 at 06:13
  • @Xinming Might be a late comment, because that's what the `append` method is intended to do. `self = self.next` is an assignment statement, it doesn't modify the node object `self` references to, that's why `head.val` is still `1`. What actually happens is variable `self` is reassigned another node object that was originally referenced by `self.next`. So yeah, the `head` (`Node(1)`) won't become `Node(2)` as you might want. – oeter Mar 07 '23 at 17:26
0

Python passes the value of a reference to an object when making a call instead of actually passing the object reference itself. In this case, self is just a local variable with a copy of a reference to the Node object that the get method is bound to, so if you assign to self with something else (self.next in your case), all that happens is for the local variable self to hold a reference to a different object, but the object that self originally referred to, as well as the reference to the object from the caller, remains untouched.

blhsing
  • 91,368
  • 6
  • 71
  • 106
  • 1
    Thanks for the detailed explanation! Clear to me now. – Xinming Sep 10 '18 at 01:54
  • "Python is neither call-by-value nor call-by-reference. Instead, it passes the value of a reference when making a call." That is exactly pass-by-value. Every value in Python (every variable, the result of evaluating any expression, etc.) is a reference, and when you pass a value, i.e. a reference, it is passed by value. The semantics of passing and assigning in Python are identical to Java, and Java is universally called pass-by-value. – newacct Sep 10 '18 at 04:34
  • link to the Java semantics question: https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value – iamanigeeit Sep 10 '18 at 06:25
  • @newacct Indeed. Thanks for the correction. – blhsing Sep 10 '18 at 06:29
  • @newacct these semantics are technically called ["call by sharing", or "call by object sharing"](https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sharing). – juanpa.arrivillaga Sep 10 '18 at 06:32