Are Python Function Pass-by-Value, Pass-by-Reference, or a Combination of Both?

I’ve seen many misconceptions about this even in Python lessons and tutorials that teach about the topic.

Let’s first take a look at what it all means.

In a pass-by-reference call, if the function makes an assignment to an argument, the original passed variable also changes.

In a pass-by-value call, if the function makes an assignment to an argument, only a local copy changes and the original stays the same.

Here is an example with a simple with a Python function:

def reset(z):
    z = 0

Now let’s this function:

x = 10  # <-- This is the original variable
reset(x)
print(x)

With pass-by-reference, this code would print 0.

With pass-by-value, this code would print 10.

What does Python do?

10

Python prints a 10! It’s pass-by-value.

The misconception comes with mutable objects such as lists. A mutable object is an object that can change its internal state.

In a list, when we assign a value at an index, we change the inside of the list:

lst = [1, 2, 3]
lst[1] = 20
print(lst)

lst is now,

[1, 20, 30]

It is possible to change the internal state of an object from inside a function, but not the object the variable is assigned to.

Here is a function that changes the first item of a list:

When we use it on a list, x = [1, 2, 3], the list changes. The variable x still points to the same list, it’s just that one of it’s elements was changed.

def change_list(lst):
  lst[1] = 20
x = [1, 2, 3]
change_list(x)
print(x)
[1, 20, 30]

However, if an argument is reassigned to a different list, the original variable stays the same:

def reassign_list(lst):
  lst = [4, 5, 6]
x = [1, 2, 3]
reassign_list(x)
print(x)  # x stays [1, 2, 3]
[1, 2, 3]

We assigned the argument a new list object inside the function, but Python prints the original object of [1,2,3]. So it’s still pass-by-value. Python is only ever pass-by-value.