Python: Pass By Value or Pass By Reference?
One of the most common question asked by Python students is ‘How to pass the object by value or by reference in a Python method?’ For most of us, knowing answer for this question is one of the milestone achievement in Software Development. I want to answer this question once for all in simplest words possible. Most of the people who have this question come from either C/C++ or Java background. I as a hardcore C/C++ developer I got nervous when I found out that there’s nothing called ‘Pass by Reference’ or ‘Pass By Value’ as such. So I started digging into the question. Did some experiments myself, which I will share in this post.
First thing first, according to official Python documentation, Python neither passes by object nor by reference. Python passes by ‘Assignment‘. What it basically means is that, the parameter is actually reference to the object. In other words variables are nothing but just names assigned to or bound to an object. There there is no relation between caller and callee. So, ampersand ‘&’ doesn’t help in Python as, the name of the parameter has no alias with the object. So, simply we can’t pass by value or by reference in python, but we pass by assignment.
But, there’s no reason to get disheartened or nervous about this. That’s what I have learnt from my experience with python. There are ways to works around it. Especially if you are worried about memory management, as a beginner I will recommend not to worry about it. Python has its own garbage collector which takes care of unbound objects when a variable gets reassigned. If you are worried about a variable getting reassigned, python believes ion the philosophy of ‘we are all adults here and we know what to do and what not to do with a variable’. Certainly reassigning the variable obviously doesn’t help.
So, the question is what to do? Even though Python doesn’t recognize a variable passed as value or reference, it recognizes variables in two different types ‘Mutable‘ and ‘Immutable‘. Immutable objects are safe from change, i.e. the contents of objects cannot be changed within a method. Examples of mutable objects are strings, numbers, tuples, None. While, Mutable objects are the objects of which contents can be changed within a method. Examples of mutable objects are lists, dictionaries, class instances etc.
Please try following example to understand what do I mean by mutable and immutable objects.
mutableVar1 = ["I","Am","Mutable"] immutableVar1 = "Immutable String" def reAssignTheVar(var): var = "New Variable" def changeTheVar(var): var.append("!") print("Mutable Var before reassigning") print(mutableVar1) print("Mutable Var after reassigning") reAssignTheVar(mutableVar1) print(mutableVar1) print("Immutable Var before reassigning") print(immutableVar1) print("Immutable Var after reassigning") reAssignTheVar(immutableVar1) print(immutableVar1) print("\n\n***********************************\n\n") print("Mutable Var before changing") print(mutableVar1) print("Mutable Var after changing") changeTheVar(mutableVar1) print(mutableVar1) print("\n\n***********************************\n\n")
Now, how we solve this problem? Obvious way is to reassign the variable and return it like
def reAssignAndReturn(var): var = "new value" return var myVar = "old value" print("Var before reassigning") print(myVar) myVar = reAssignAndReturn(myVar) print("Var after reassigning") print(myVar)
In case of strings, if you want to manipulate content of a string. A work around is to convert string into a list, make changes, reformulate list into a string and return the string.
def manipulateStringArray1(var,oldChar,newChar): var = list(str(var)) for i in range(0,len(var)): if var[i] == oldChar: var[i] = newChar return ''.join(var) def manipulateStringArray2(var,oldChar,newChar): var = str(var).split() for i in range(0,len(var)): if var[i] == oldChar: var[i] = newChar return ' '.join(var) str1 = "I am a string" print("String after replacing space with '_'") print(manipulateStringArray1(str1," ","_")) str2 = "My name is Rohit" print("String after replacing a word with another word/s") print(manipulateStringArray2(str2,"Rohit","Rohit Bapat"))
So, I think we have found the answer to the question ‘Does Python pass object by value or by reference?’ once for all.
Python has its way and we must work to get the best out of it without getting stuck or confused.