Python Pass by Reference and by Value

By Rex Resurreccion Oct 10, 2019
Understand Python pass by reference and by value

Python pass by reference and pass by value behavior is probably one of the confusing topics for new (even for experienced) programmers that sometimes being overlooked.

For example, if you came from a PHP background, the default behavior of a parameter in a function is pass by value, and to make it pass by reference, you need to put an ampersand  in front of the parameter.

<?php
function foo(&$pets){
  //modify $pets
}

Pass by Reference and by Value

In Pass By Value you are passing the object’s value and anything you do with the parameter does not affect the Object.

When you Pass By Reference on the other hand, you are actually passing the ID of your object. The ID is the address of the object in your computer’s memory, hence anything you do with the parameter will affect the original value in the Object.

Mutable Object and Variable Assignment

An example of Python’s mutable objects are list, dictionary (dict) and set. For example below, variable “a” is a dictionary, and we are assigning it to variable “b”.

a = {'dog': 'pug'}
b = a
b['dog'] = 'chihuahua'
>>> print(a) 
{'dog': 'chihuahua'}

Our variable “a” did changed to chihuahua! That is because both variables “a” and “b” have the same ID when we passed by reference and “a” is a mutable object type dictionary.

>>> type(a)
<type 'dict'>
>>> type(b)
<type 'dict'>
>>> id(a) == id(b)
True

Now that we know how variable assignment works in Python and how Pass by Reference affects mutable objects, let’s take a look at how we can apply parameters to a function.

To use default parameter value you must assign it during function definition. If you have required parameters, it has to be defined first followed by your optional parameters, otherwise you will get a syntax error.

SyntaxError: non-default argument follows default argument

Defining function parameters in proper order.

def foo(fruit, fav=[]):
  if fruit not in fav:
    fav.append(fruit)
    print 'fruit is not in fav'
  else:
    print 'fruit is in fav'
  return fav

a = 'apple'
b = ['banana','apple','orange']
>>> foo(a, b) # we expect fruit is in fav
fruit is in fav
>>> foo(a) # we did not pass "b" our fav will default to an empty list
fruit is not in fav
>>> foo(a) # we did not pass "b" but we got a different result
fruit is in fav

On the first and second call to function “foo” we got the expected result. However, on the third call it was different! That is because the default value of parameter “fav” is a list, which is a mutable object, and the function keeps using the same object in each call. Therefore, if we modify the value of “fav” the object will retain the value on the next instance of “foo”. Let’s verify the ID of the returned parameter “fav” below.

>>> id(foo('apple')) #first call
fruit is in fav
140092634617688
>>> id(foo('apple'))
fruit is in fav
140092634617688 #second call has the same ID

In a real program this could cause a logical error because we did not get the intended result. To workaround this behavior, we can use a placeholder in our optional parameter instead of modifying the value inside the list object.

Parameter Placeholder

Now we will implement the placeholder in our function “foo”. Here we used “None” as our placeholder value (You can also use an empty “object()”).

def foo(fruit, fav=None):
  if fav is None:
    fav = []
  if fruit not in fav:
    fav.append(fruit)
    print 'fruit is not in fav'
  else:
    print 'fruit is in fav'
  return fav

a = 'apple'
b = ['banana','apple','orange']
>>> foo(a, b) # we expect fruit is in fav
fruit is in fav
>>> foo(a) # we did not pass "b" our fav will default to an empty list
fruit is not in fav
>>> foo(a) # we did not pass "b" and we got the same result
fruit is not in fav

This time we got the expected result in all calls to our function “foo”. Also notice that we checked if the object has changed in our parameter “fav” using the comparison “is None”.

Conclusion

In Pass by reference you are passing the identity of the object. Mutable objects can change value after it was declared, in contrast, there is also an Immutable object. Use a placeholder instead of modifying the value of a parameter inside your function to avoid unexpected result.

Tags:
© YippeeCode.com 2020