Tail of Godzilla
Tail of Godzilla

Reputation: 551

Why changing object type affects Python's behavior on pass-by-reference?

I would have expected the following code:

def a(l):
    l.append(3)

def b(l):
    l = 5

def c(l):
    l = (2,-2)

numbers = [1,2,3,4,5]
a(numbers)
print(numbers)
b(numbers)
print(numbers)
c(numbers)
print(numbers)

to print:

[1, 2, 3, 4, 5, 3]
5
(2,-2)

but it prints:

[1, 2, 3, 4, 5, 3]
[1, 2, 3, 4, 5, 3]
[1, 2, 3, 4, 5, 3]

why??

EDIT:

It is because of difference between pass by reference and call by sharing!

Upvotes: 0

Views: 67

Answers (3)

JohanL
JohanL

Reputation: 6891

Most values in Python are immutable, which means they cannot be updated. This means that the value of the variable cannot change. However, it is possible to make a reference point to a new (immutable) value. Thus, when writing

i = 4
i = 5

you are in fact first making i point to the (immutable value) 4, then pointing i to the (equally immutable) value 5.

Lists, however, are mutable. That means we can do

L = [3,4]
L.append(5)

and have the same referenced object updated with a new value [3, 4, 5].

When calling a function, the values of e.g. i and L are not passed directly to the function. Instead references to the values are passed. The original references are saved also in the calling environment, to be restored when the called function returns.

Looking at your functions that means:

def a(l):
    l.append(3)

Here, the reference l is not changed/updated, since append will change the value of what is referenced. Thus, when returning from the function l will be "restored" to the same value as used in the function, and the list is updated.

def b(l):
    l = 5

def c(l):
   l = (2,-2)

In these two function however, the reference l is made to point to something new, due to the assignment. Thus we have modified the reference itself. Then, when returning, the reference is restored to point to the value used in the calling scope. Therefore, l will be the original list again, and the reference value used in the function will be out-of-scope and any value pointed to by that reference will be lost/deleted.

Thus, this is more than just a semantic difference than called by reference or called as reference or called by sharing which has to do with the immutability of types and how references work in Python.

Upvotes: 1

cdlane
cdlane

Reputation: 41872

The way I view this is that Python, like C and Java, effectively does pass by value. In the case of your a() function, you are passing a reference by value. There is no pass by reference there.

Perl, on the other hand, does pass by alias which has some similar behaviors to pass by reference.

I've seen a computer science professor incorrectly claim Objective-C passes by reference because the text book says so, without thinking it through. But it's still just pass by value.

Upvotes: 3

Alexander
Alexander

Reputation: 109546

The first method (a) is actually modifying the list item passed via l.append(...)

Both the second and third methods (b and c) reassign the parameter l to a new value. This reassignment is local to the function and is not returned, hence it is lost. When you print numbers after executing b(numbers) and c(numbers), you are printing the value that was modified by method a.

Upvotes: 2

Related Questions