In my recent project, I needed to migrate c# code which uses reference parameters. Unfortunately, python does not support reference parameters - In this article we will see how can we mimic their semantics in python.

About reference parameter

A reference parameter is a local variable which points to the same storage location as the variable which was given as argument in function invocation.

We can think of a reference parameter x as an alias to the y variable that was given as argument in function invocation. Thus, any changes we do to x in the function are automatically reflected in y. Reference parameters are common in several programing languages (i.e c# or c++).

reference parameters in python

Let’s define the terms in definition

Local variables, parameters and arguments

  • A function’s local variable is a variable which can be used only in the function body.

  • A function’s parameter is specific type of function’s local variable which initial value is given in function invocation.

  • A function’s argument is the initial value which is given to the parameter in function invocation. This value assigned to function’s parameter at the beginning of the execution of the function.

Consider the following code:

local variable,parameter and argument
def sumSquare(x1 , x2):
  sum = x1 + x2
  return sum * sum
#print x1  # will raise `NameError: name 'x1'  is not defined`
#print x2  # will raise `NameError: name 'x2'  is not defined`
#print sum # will raise `NameError: name 'sum' is not defined`
print sumSquare(1, 2) # <== A
print sumSquare(3, 4) # <== B

The x1, x2 are parameters of sumSquare function while sum is a local variable of sumSquare function. The parameters and local variables can only be used in function body.

In A1 we call the sumSquare function with 1 and 2 arguments – Thus the initial value of x1 parameter is 1 and the initial value of x2 parameter is 2.

In A2 we call the sumSquare function with 3 and 4 arguments – Thus the initial value of x1 parameter is 3 and the initial value of x2 parameter is 4.

About value parameter (passing by value)

Python supports only value parameters. A value parameter x is local variable which initial value is the argument given in the in function invocation.

The argument can be the value of expression or a variable. In the later case, any change in the parameter value is not reflected in the variable.

Consider the following code:

value parameter
def double(x1):
  print 'x1={0} [ Enter  double] '.format(x1)
  x1 = 2 * x1
  print 'x1={0} [ Exit   double] '.format(x1)
x2 = 2
print 'x2={0} [ Before double]'.format(x2)
double(x2)
print 'x2={0} [ After  double]'.format(x2)

The output will be:

x2=2 [ Before double]
x1=2 [ Enter  double]
x1=4 [ Exit   double]
x2=2 [ After  double]

Although the value of x1 changed in the function double, This does not affect the value x2 which was the argument of the function.

About reference parameters (passing by reference)

Sometimes, reference parameters semantics allows to simplify the code and express our thoughts clearer.

As discussed, We can think of reference parameter x as an alias to the y variable that was given as argument in function invocation. Thus, any changes we do to x in the function, are automatically reflected in y.

Suppose we want convert a string to int

The motive for reference parameter
def parseInt(ss):
    return int(ss)
print parseInt("2") * parseInt("a")

When running an exception will raised: ValueError: invalid literal for int() with base 10: 'a'

It will be helpful if the function will return whether the given string represents valid number and update the second parameter to the converted value.

def tryParseInt(ss,vv):
    try:
        vv = int(ss)
        return True
    except:
        return False
v1 = 0
v2 = 0
if tryParseInt("2",v1) and tryParseInt("3",v2):
    print v1*v2 # will print 0

Unfortunately, this does not work since python support only value parameter. Thus, any change in parameter does not affect the variable that was given as an argument.

Please note, we can not change the value of the variable which was given as an argument - but we can change its attributes. using this observation, we will use the following class to overcome this issue.

reference parameter
class Holder:
    def __init__(self,value=None):
        self.value = value

With this class at hand, let’s modify the previous function:

class Holder:
    def __init__(self,value=None):
        self.value = value
def tryParseInt(ss,vv):
    try:
        vv.value = int(ss)
        return True
    except:
        return False
v1 = Holder(0) ; v2 = Holder(0)
if tryParseInt("2",v1) and tryParseInt("3",v2):
    print v1.value*v2.value # print 6

This will work since we do not change value of the parameter – we change the value of its attribute value.

Summery

Although python does not support reference parameters we can mimic this feature with a little effort. The Holder class is viable tool when migrating code from a language which supports reference parameters to python.