#Day9 - Pass by Value, Pass by Reference, and Python's Pass by Object Reference
Tags: python, 100daysofcode, codenewbie, programming
Published: 2021-03-30 00:50:52

Before defining Pass by Reference and Pass by Value, let's consider an analogy.

Let's say you have a notebook with notes for MAT188 or any subject 📓 . A friend of yours asks for your notebook. You agree to share your notebook with them. There are a couple of ways you could give your notebook, 
- You could get a Xerox Copy or a Photocopy of your notebook and share the copy with them 
- You could give your own notebook 

Consider the case where you gave your friend a copy of your notebook. If they were to make any changes to the notes or add any notes, they could do so in their copy. Your original notebook would be unaffected. However, in this scenario, it took you some time and space (2 books instead of 1) to actually make a copy of your notebook. If all your friend did was add a single page, you went through all the hassle of creating a copy for almost nothing.

Now consider the second case. Instead of creating a copy, you gave your own notebook to your Friend. In this case, you didn't have to spend any time making a copy of your book and there is only one book (No copy exists). However, if your friend were to make any changes to your notes, they'd have to do so in your original notebook. So when they return your notebook back to you, your notebook would have their change as well. 

The notebook is the argument/parameter passed to the function. The first case where you give your friend a copy of your notebook is similar to **pass by value** while the second case where you give your friend your original notebook is **pass by reference**.

### Pass by Reference

When you pass a parameter by reference, any changes made to the parameter inside the function are reflected outside the function as well.
- Since you don't create a copy and instead pass a reference to the variable, you end up saving the time it would have taken to create a copy of the variable
- Since no copy is created, no extra space is taken
- Since the changes are reflected outside the function as well, in a way you "lose" your original variable

### Pass by Value
A copy of the variable is passed as a parameter. Any changes made to this parameter is NOT reflected outside the function 
- Since you are creating a copy of your variable, it takes more time and space
- Since your original variable remains unaffected, you do not "lose" your variable

Below is a gif that depicts Pass by Value vs Pass by Reference

![pass-by-reference-vs-pass-by-value-animation.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1617058835279/l3HQwS2O2.gif)

### What about Python?

Python is neither Pass by Reference nor is it Pass by Value. It is pretty unique, it is pass by Object Reference



![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1617059841775/D5Gf6Or_M.png)
Below is the output of the above code
```
Defined Variable a
Variable a is located at address 9785184
In function
Variable x is located at address 9785184
Variable a is located at address 9785184
```

**id()** is used to get an integer representation of a variable's memory address in Python. 
As you can see, the memory address of **variable a** and **parameter x** is the same. This means they are located at the same address. However, this is not Pass by Reference. Look at the code below, where we modify the **parameter x ** inside the function.


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1617060156423/70ZwTYcTB.png)
Below is the output of the above code

```
Defined Variable a
Address of a is 9785184
value of a is 10
Inside Function
Address of x is 9785184
Modifying variable x
Address of x is 9785504
value of x is 20
value of a is 10
```
After we modify the **parameter x** inside the function, the memory address of **parameter x** changes. And as you can see in the last two statements printed, the value and x and a are different. However, this is not Pass by Value either since the memory address of the **parameter x** and **variable a** are initially the same.
This is Python's Pass by Object Reference.

In Python everything is object and objects are either mutable or immutable. To know more about mutability, refer to my article on Day 5.

- If the object being passed as a parameter is mutable, the changes made inside the function are reflected outside the function.  Example of mutable objects : Lists, Dictionaries, Sets
- If the object being passed as a parameter is immutable, the changes made inside the functional are NOT reflected outside the function. Example of immutable objects: Int, Float, String, Tuple, Frozen Sets

We have already seen the case where we pass an integer as a parameter. Now we will see what happens when we pass a mutable object like a List as a parameter.


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1617064445733/Euai2LgJu.png)
```
original_lst is [1, 2]
The address of original_lst is 139792761916992
Inside function
The address of lst is 139792761916992
Modifying the variable lst
The address of lst is 139792761916992
Lst is [1, 2, 3, 4]
The address of original_lst is 139792761916992
original_lst is [1, 2, 3, 4]
```

The address of the **parameter lst** doesn't change even after we modify it. Additionaly, the changes made to the **parameter lst** are reflected outside the function in the  **variable original_lst** 

However, now consider the below case where we re-assign a value to the **parameter lst**

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1617062883541/8nQ79M4DK.png)

```
original_lst is [1, 2]
The address of original_lst is 140088994123264
Inside function
The address of lst is 140088994123264
Modifying the variable lst
The address of lst is 140088993495680
Lst is [3, 4]
The address of original_lst is 140088994123264
original_lst is [1, 2]
```

As you can see, the memory address of the **parameter lst** change after modification and the values of **lst** and **original_lst** are different.

Re-assigning a parameter, irrespective of whether it's mutable or not will change it's memory address. As a result, the changes won't be reflected outside the function.

### How to Pass Values by Reference in Python?
What if you want a pass an immutable value by reference? or if you want the re-assignment inside the function to be reflected outside the function as well?

We can use re-assignment outside the function to mimic a Pass by Reference



![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1617064651608/nVsR1tWr0.png)
```
Inside func1
After calling func1, original_str is Original str
Inside func1
After calling func2, original_str is Original str.........Updating str
```

- After calling function **func1**, the variable **original_str** remaining unchanged. 
- In the function **func2**, we return the parameter **string** and re-assign the variable **original_str**. This mimics Pass by Reference.

### Summary
- When we pass a parameter by reference, any changes made to it inside the function are reflected outside the function as well
- When we pass a parameter by value, any changes made to it inside the function are NOT reflected outside the function
- Python is Pass by Object Reference
- If the parameter is a mutable object, any changes made to it inside the function are reflected outside the function
- If the parameter is an immutable object, any changed made to it inside the function are NOT reflected outside the function
- If we re-assign the parameter inside the function, the changes will NOT be reflected outside the function irrespective of whether the parameter is mutable or immutable
- To mimic Pass by Reference in Python, we can re-assign the variable to the return value of the function.