Are Python Functions call by value or call by reference?

Probhakar
4 min readJan 1, 2021

--

An effort to demystify Python object referencing mechanism

Long time back I posted one question on StackOverflow

fig 1

It seems foo_1() was not able to modify the variable but foo_2() was. People may think that since some_variable is an int that is why it is passed by value and some_list is a list(or vector) that is why it is used as a reference.

Does python do all these under the hood? How does Python know when to call by value and when to call by reference?

I heard some guys on Twitter saying Python function works by call by reference mechanism. If this is true, then both some_variable and some_list should be modified, isn’t it? Later, I came to know that Python works on a totally different mechanism, it is not simply call by value or call by reference like C, C++. Today I will try to demystify this.

Everything in python is an object. When we define a variable like this

fig 2

What is happening under the hood is a list object is created with int objects with int values 11,22,33,44 and finally the list object reference is stored in the variable some_list.

fig 3

or

fig 4
fig 5

That means the variable name that we declare is just a channel to go to the object. We can see the attributes of an object by simply

fig 6

As you can see some_variable is referring to an int object with all integer object attributes.

If we assign a String to some_variable, a new object will be created and some_variable will refer to that String object.

fig 7

So it can be thought of as any variable that we declare in Python is a reference to an object. Similar to C

fig 8

But there is a caveat. Every object in Python has id which uniquely determines an object.

fig 8

Now let’s create two variables a,b

fig 9

Do you think a and b refer to the same object or a different object?

fig 10

That means, whatever mathematical calculation we are doing the end result is 2, Python doesn’t create another int object with value 2 but a,b both referring to the same object.

fig 11

This is a big difference in implementation from C, C++. Although we can forcefully create a different object using shallow copy or deep copy.

Now coming back to our problem, let’s print the ids to see what is happening.

fig 12

And in case of some_list

fig 13

It is seen that in case of some_variable the id is changed, but in case of some_list, the id remains same.

This is happening due to the fact that the list is not getting changed as a whole, but one of its elements is getting changed. Changing a single element doesn't alter the whole list object. But in the case of some_variable, since we are creating a new object with the value 0, the id is getting changed.

Let’s see Python and C implementation and their differences

fig 14

The difference in implementation is explained below

fig 15

That means when we declared

a = 0

Python doesn't destroy the old value, but it creates a new int object with value 0 and any pointer that is pointing to the int object 77 is unaltered. This referencing is crucial for garbage collection also. Python keeps track of the number of references of an object. If the number of references is 0, that means a programmer can never refer to this object, so Python’s garbage collector will be more than happy to free the space, but this is a story of a different day.

I hope this article will be helpful.

--

--

Responses (1)