How Call by Value and Call by Reference Work in Python?
Tags: programming, python, beginners
Published: 2021-11-15 15:12:49

In this *Article* we're going to understand how call by value and call by reference work in *python*

Let's first understand what is call by value and call by reference

* **Call By Value :-**
In Call by value the value(copy) of the parameters passed as *formal argument* ina *function* instead of the variable itself, so in this case if any modification applied to the function parameters it will not be *reflected* on the actual variable.**

*let's take example in C programming langauge to better understand call by value and call by reference*
*Example :-*
```
#include <stdio.h>

void call_by_value(int a , int b){
    a = 44;
    b = 55;
}

int main() {
    int a  = 1;
    int b = 2;
    printf("value of a and b before function call :- %d and %d",a,b);
    call_by_value(a, b);
    printf("\nvalue of a and b after function call :- %d and %d",a,b);
    return 0;
}
Output :-
value of a and b before function call :- 1 and 2
value of a and b after function call :- 1 and 2
```
In above example the value of varible a and b not modified because a copy of a,b passed instead of their addresses



* **Call By Reference :-**
In Call By Reference, the address(actual varible) of the variable is passed into the function call as the actual parameter.

So, if any modification applied to the function parameters it will  be *reflected* on the actual variable.**

*Example :-*
```
#include <stdio.h>

void call_by_reference(int *a , int *b){
    *a = 44;
    *b = 55;
}

int main() {
    int a  = 1;
    int b = 2;
    printf("value of a and b before function call :- %d and %d",a,b);
    call_by_reference(&a, &b);
    printf("\nvalue of a and b after function call :- %d and %d",a,b);
    return 0;
}
Output :-
value of a and b before function call :- 1 and 2
value of a and b after function call :- 44 and 55
```
In above example the address of varible a and b  using __&__ followed by variable name , where  in function defination
 __*__ followed parameter known as *pointer variable* which used
to storing addresses, because of this values in varible *a* and *b* is modified.

Now we have seen what is *call by value and call by reference* with example

But, *Python* programming language uses the mechanism of the **call-by-object** and also **call by object reference**.

Each object whenever it is instantiated ,it is assigned  unique **id**  and its type if defined at *runtime* and *id(object)* returns a unique identity (integer value) of that object.

to move further into the topic first we have to understand *mutable* object and *immutable* object in python.

* **Mutable Objects**
Datatypes that can be modified or if there state can be changed those objects are known as *Mutable* datatype
like **(list, dictionaries, set)** .

* **Immutable Objects**
Datatypes that cannot be modified or if there state cannot be changed those objects are known as *Immutable* datatype like **(int, float, bool, string, unicode, tuple). 


**So when *Mutable* objects are passed to the *function* call then it is treated as **call by value**.**

**And When *Immutable* objects  are passed to the *function* call  and there value is modified then it is treated as **call by reference**.**

For the  sake of simplicity we're going to use the word call by value and call by reference instead of (call by object) and (call by object reference) respectivly.

let's take examples for call by reference and call by value

**Example :- Call by reference (with Immutable objects (int, float, bool, string) and no object state modified) in python**
```
num1  = 43
num2 = 12.44
num3 = False
name = 'hello'
print("Id in main function scope")
print(f"id of num1  = {id(num1)}")
print(f"id of num2  = {id(num2)}")
print(f"id of num2  = {id(num3)}")
print(f"id of name = {id(name)}")


def call_by_reference(num1,num2,num3,name):
  print("\nId within function")
  print(f"id of num1  = {id(num1)}")
  print(f"id of num2  = {id(num2)}")
  print(f"id of num2  = {id(num3)}")
  print(f"id of name = {id(name)}")


call_by_reference(num1,num2,num3,name)

Output :-
Id in main function scope
id of num1  = 94157957099328
id of num2  = 140438713493200
id of num2  = 94157956423968
id of name = 140438848940272

Id within function
id of num1  = 94157957099328
id of num2  = 140438713493200
id of num2  = 94157956423968
id of name = 140438848940272

```

So we can see that the id's the objects *(num1, num2, num3)* has not change becuase have not applied modification to those objects.

**Example :- Call by reference (with Mutable objects (list ,dict) and object state modified) in python**

```
names = ['ram', 'shyam', 'bharat']
d =  {'bob':21,'max':22}
print("Id in main function scope")
print(f"id of names list  = {id(names)}")
print(f"id of d dict  = {id(d)}")

def call_by_reference(name, d):
  print("Id within function")

  d['sam'] = 12
  names.append('john')

  print("\nModified Objects id :-")
  print(f"id of names list  = {id(names)}")
  print(f"id of d dict  = {id(d)}")

call_by_reference(names, d)
print("Modfied list and dict")
print(f"names =   {names}")
print(f"dict = {d}")

Output :-

Id in main function scope
id of names list  = 140439297460096
id of d dict  = 140438712179600
Id within function

Modified Objects id :-
id of names list  = 140439297460096
id of d dict  = 140438712179600
Modfied list and dict
names =   ['ram', 'shyam', 'bharat', 'john']
dict = {'bob': 21, 'max': 22, 'sam': 12}

```

We can see even after modifying the objects state the *id's* of the object remains unchanged because the objects datatype are *mutable* objects here by ,even if the object state is modified
it is treated as call by reference(call by object reference).

**==============================================**

**Example :- Call by Value (with Immutable objects (int, float, bool, string) and object state modified) in python**
```
num1  = 43
num2 = 12.44
num3 = False
name = 'hello'
print("Id in main function scope")
print(f"id of num1  = {id(num1)}")
print(f"id of num2  = {id(num2)}")
print(f"id of num2  = {id(num3)}")
print(f"id of name = {id(name)}")


def call_by_value(num1,num2,num3,name):
  print("\nId within function")
  num1 = 1
  num2 = 2
  num3 = 3
  name = 'sam'
  print("Modified Objects id")

  print(f"id of num1  = {id(num1)}")
  print(f"id of num2  = {id(num2)}")
  print(f"id of num2  = {id(num3)}")
  print(f"id of name = {id(name)}")


call_by_value(num1,num2,num3,name)
print("\Unmodified int, float, bool, string objects value in global scope")
print(f'num1 = {num1}')
print(f'num2 = {num2}')
print(f'num3 = {num3}')

Output :-
Id in main function scope
id of num1  = 94157957099328
id of num2  = 140438713494320
id of num2  = 94157956423968
id of name = 140438848940272

Id within function
Modified Objects id
id of num1  = 94157957097984
id of num2  = 94157957098016
id of num2  = 94157957098048
id of name = 140438713157936

Unmodified int, float, bool, string objects value in global scope
num1 = 43
num2 = 12.44
num3 = False

```
In the above example we can see that after modifying the *Immuatable* objects the object *id's* were diffrent , this is because we cannot modify the value of *Immutables* and because of this new 3 objects named (*num1, num2, num3, name*) where created in the function *local* scope after the function call we have also print the value to verify the  objects in the *global* scope remain unchanged.


**Example :- Call by Value (with Immutable objects (tuple) and object state modified) in python**
```
names = ('ram', 'shyam', 'bharat')
print("Id in main function scope")
print(f"id of names tuple  = {id(names)}")

def call_by_value(name, d):
  print("Id within function")
  names = ('ram','shyam','bharat','john')
  print(f"modified object value \n{names}")
  print("\nModified Objects id :-")
  print(f"id of names tuple  = {id(names)}")

call_by_value(names, d)
print("\nUnchanged tuple object in global scope")
print(f"names = {names}")

Output :-
Id in main function scope
id of names tuple  = 140438712974144
Id within function
modified object value 
('ram', 'shyam', 'bharat', 'john')

Modified Objects id :-
id of names tuple  = 140438712255888

Unchanged tuple object in global scope
names = ('ram', 'shyam', 'bharat')
```

In the above example we can have assigned a new *tuple* with same elements + one more element because (*tuple* datatype does not support  any *add* method) andchecked the object *id* which is diffrent because a new object gets created and also the global object remain unchanged because of it's *Immutable* nature.


With this example we have come to an end
hope you all have understood the topics
covered in this article.

:-)