How do I pass a variable by reference?

Viewed 1824164

Are parameters passed by reference or by value? How do I pass by reference so that the code below outputs 'Changed' instead of 'Original'?

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.change(self.variable)
        print(self.variable)

    def change(self, var):
        var = 'Changed'
37 Answers

Arguments are passed by assignment. The rationale behind this is twofold:

  1. the parameter passed in is actually a reference to an object (but the reference is passed by value)
  2. some data types are mutable, but others aren't

So:

  • If you pass a mutable object into a method, the method gets a reference to that same object and you can mutate it to your heart's delight, but if you rebind the reference in the method, the outer scope will know nothing about it, and after you're done, the outer reference will still point at the original object.

  • If you pass an immutable object to a method, you still can't rebind the outer reference, and you can't even mutate the object.

To make it even more clear, let's have some examples.

List - a mutable type

Let's try to modify the list that was passed to a method:

def try_to_change_list_contents(the_list):
    print('got', the_list)
    the_list.append('four')
    print('changed to', the_list)

outer_list = ['one', 'two', 'three']

print('before, outer_list =', outer_list)
try_to_change_list_contents(outer_list)
print('after, outer_list =', outer_list)

Output:

before, outer_list = ['one', 'two', 'three']
got ['one', 'two', 'three']
changed to ['one', 'two', 'three', 'four']
after, outer_list = ['one', 'two', 'three', 'four']

Since the parameter passed in is a reference to outer_list, not a copy of it, we can use the mutating list methods to change it and have the changes reflected in the outer scope.

Now let's see what happens when we try to change the reference that was passed in as a parameter:

def try_to_change_list_reference(the_list):
    print('got', the_list)
    the_list = ['and', 'we', 'can', 'not', 'lie']
    print('set to', the_list)

outer_list = ['we', 'like', 'proper', 'English']

print('before, outer_list =', outer_list)
try_to_change_list_reference(outer_list)
print('after, outer_list =', outer_list)

Output:

before, outer_list = ['we', 'like', 'proper', 'English']
got ['we', 'like', 'proper', 'English']
set to ['and', 'we', 'can', 'not', 'lie']
after, outer_list = ['we', 'like', 'proper', 'English']

Since the the_list parameter was passed by value, assigning a new list to it had no effect that the code outside the method could see. The the_list was a copy of the outer_list reference, and we had the_list point to a new list, but there was no way to change where outer_list pointed.

String - an immutable type

It's immutable, so there's nothing we can do to change the contents of the string

Now, let's try to change the reference

def try_to_change_string_reference(the_string):
    print('got', the_string)
    the_string = 'In a kingdom by the sea'
    print('set to', the_string)

outer_string = 'It was many and many a year ago'

print('before, outer_string =', outer_string)
try_to_change_string_reference(outer_string)
print('after, outer_string =', outer_string)

Output:

before, outer_string = It was many and many a year ago
got It was many and many a year ago
set to In a kingdom by the sea
after, outer_string = It was many and many a year ago

Again, since the the_string parameter was passed by value, assigning a new string to it had no effect that the code outside the method could see. The the_string was a copy of the outer_string reference, and we had the_string point to a new string, but there was no way to change where outer_string pointed.

I hope this clears things up a little.

EDIT: It's been noted that this doesn't answer the question that @David originally asked, "Is there something I can do to pass the variable by actual reference?". Let's work on that.

How do we get around this?

As @Andrea's answer shows, you could return the new value. This doesn't change the way things are passed in, but does let you get the information you want back out:

def return_a_whole_new_string(the_string):
    new_string = something_to_do_with_the_old_string(the_string)
    return new_string

# then you could call it like
my_string = return_a_whole_new_string(my_string)

If you really wanted to avoid using a return value, you could create a class to hold your value and pass it into the function or use an existing class, like a list:

def use_a_wrapper_to_simulate_pass_by_reference(stuff_to_change):
    new_string = something_to_do_with_the_old_string(stuff_to_change[0])
    stuff_to_change[0] = new_string

# then you could call it like
wrapper = [my_string]
use_a_wrapper_to_simulate_pass_by_reference(wrapper)

do_something_with(wrapper[0])

Although this seems a little cumbersome.

It is neither pass-by-value or pass-by-reference - it is call-by-object. See this, by Fredrik Lundh:

http://effbot.org/zone/call-by-object.htm

Here is a significant quote:

"...variables [names] are not objects; they cannot be denoted by other variables or referred to by objects."

In your example, when the Change method is called--a namespace is created for it; and var becomes a name, within that namespace, for the string object 'Original'. That object then has a name in two namespaces. Next, var = 'Changed' binds var to a new string object, and thus the method's namespace forgets about 'Original'. Finally, that namespace is forgotten, and the string 'Changed' along with it.

Think of stuff being passed by assignment instead of by reference/by value. That way, it is always clear, what is happening as long as you understand what happens during the normal assignment.

So, when passing a list to a function/method, the list is assigned to the parameter name. Appending to the list will result in the list being modified. Reassigning the list inside the function will not change the original list, since:

a = [1, 2, 3]
b = a
b.append(4)
b = ['a', 'b']
print a, b      # prints [1, 2, 3, 4] ['a', 'b']

Since immutable types cannot be modified, they seem like being passed by value - passing an int into a function means assigning the int to the function's parameter. You can only ever reassign that, but it won't change the original variables value.

You got some really good answers here.

x = [ 2, 4, 4, 5, 5 ]
print x  # 2, 4, 4, 5, 5

def go( li ) :
  li = [ 5, 6, 7, 8 ]  # re-assigning what li POINTS TO, does not
  # change the value of the ORIGINAL variable x

go( x ) 
print x  # 2, 4, 4, 5, 5  [ STILL! ]


raw_input( 'press any key to continue' )

In this case the variable titled var in the method Change is assigned a reference to self.variable, and you immediately assign a string to var. It's no longer pointing to self.variable. The following code snippet shows what would happen if you modify the data structure pointed to by var and self.variable, in this case a list:

>>> class PassByReference:
...     def __init__(self):
...         self.variable = ['Original']
...         self.change(self.variable)
...         print self.variable
...         
...     def change(self, var):
...         var.append('Changed')
... 
>>> q = PassByReference()
['Original', 'Changed']
>>> 

I'm sure someone else could clarify this further.

Since dictionaries are passed by reference, you can use a dict variable to store any referenced values inside it.

# returns the result of adding numbers `a` and `b`
def AddNumbers(a, b, ref): # using a dict for reference
    result = a + b
    ref['multi'] = a * b # reference the multi. ref['multi'] is number
    ref['msg'] = "The result: " + str(result) + " was nice!"
    return result

number1 = 5
number2 = 10
ref = {} # init a dict like that so it can save all the referenced values. this is because all dictionaries are passed by reference, while strings and numbers do not.

sum = AddNumbers(number1, number2, ref)
print("sum: ", sum)             # the returned value
print("multi: ", ref['multi'])  # a referenced value
print("msg: ", ref['msg'])      # a referenced value

Since it seems to be nowhere mentioned an approach to simulate references as known from e.g. C++ is to use an "update" function and pass that instead of the actual variable (or rather, "name"):

def need_to_modify(update):
    update(42) # set new value 42
    # other code

def call_it():
    value = 21
    def update_value(new_value):
        nonlocal value
        value = new_value
    need_to_modify(update_value)
    print(value) # prints 42

This is mostly useful for "out-only references" or in a situation with multiple threads / processes (by making the update function thread / multiprocessing safe).

Obviously the above does not allow reading the value, only updating it.

You can merely use an empty class as an instance to store reference objects because internally object attributes are stored in an instance dictionary. See the example.

class RefsObj(object):
    "A class which helps to create references to variables."
    pass

...

# an example of usage
def change_ref_var(ref_obj):
    ref_obj.val = 24

ref_obj = RefsObj()
ref_obj.val = 1
print(ref_obj.val) # or print ref_obj.val for python2
change_ref_var(ref_obj)
print(ref_obj.val)

Pass-By-Reference in Python is quite different from the concept of pass by reference in C++/Java.

  • Java&C#: primitive types(include string)pass by value(copy), Reference type is passed by reference(address copy) so all changes made in the parameter in the called function are visible to the caller.
  • C++: Both pass-by-reference or pass-by-value are allowed. If a parameter is passed by reference, you can either modify it or not depending upon whether the parameter was passed as const or not. However, const or not, the parameter maintains the reference to the object and reference cannot be assigned to point to a different object within the called function.
  • Python: Python is “pass-by-object-reference”, of which it is often said: “Object references are passed by value.”[Read here]1. Both the caller and the function refer to the same object but the parameter in the function is a new variable which is just holding a copy of the object in the caller. Like C++, a parameter can be either modified or not in function - This depends upon the type of object passed. eg; An immutable object type cannot be modified in the called function whereas a mutable object can be either updated or re-initialized. A crucial difference between updating or re-assigning/re-initializing the mutable variable is that updated value gets reflected back in the called function whereas the reinitialized value does not. Scope of any assignment of new object to a mutable variable is local to the function in the python. Examples provided by @blair-conrad are great to understand this.

I am new to Python, started yesterday (though I have been programming for 45 years).

I came here because I was writing a function where I wanted to have two so called out-parameters. If it would have been only one out-parameter, I wouldn't get hung up right now on checking how reference/value works in Python. I would just have used the return value of the function instead. But since I needed two such out-parameters I felt I needed to sort it out.

In this post I am going to show how I solved my situation. Perhaps others coming here can find it valuable, even though it is not exactly an answer to the topic question. Experienced Python programmers of course already know about the solution I used, but it was new to me.

From the answers here I could quickly see that Python works a bit like Javascript in this regard, and that you need to use workarounds if you want the reference functionality.

But then I found something neat in Python that I don't think I have seen in other languages before, namely that you can return more than one value from a function, in a simple comma separated way, like this:

def somefunction(p):
    a=p+1
    b=p+2
    c=-p
    return a, b, c

and that you can handle that on the calling side similarly, like this

x, y, z = somefunction(w)

That was good enough for me and I was satisfied. No need to use some workaround.

In other languages you can of course also return many values, but then usually in the from of an object, and you need to adjust the calling side accordingly.

The Python way of doing it was nice and simple.

If you want to mimic by reference even more, you could do as follows:

def somefunction(a, b, c):
    a = a * 2
    b = b + a
    c = a * b * c
    return a, b, c

x = 3
y = 5
z = 10
print(F"Before : {x}, {y}, {z}")

x, y, z = somefunction(x, y, z)

print(F"After  : {x}, {y}, {z}")

which gives this result

Before : 3, 5, 10  
After  : 6, 11, 660  

alternatively you could use ctypes witch would look something like this

import ctypes

def f(a):
    a.value=2398 ## resign the value in a function

a = ctypes.c_int(0)
print("pre f", a)
f(a)
print("post f", a)

as a is a c int and not a python integer and apperently passed by reference. however you have to be carefull as strange things could happen and is therefor not advised

Most likely not the most reliable method but this works, keep in mind that you are overloading the built-in str function which is typically something you don't want to do:

import builtins

class sstr(str):
    def __str__(self):
        if hasattr(self, 'changed'):
            return self.changed

        return self

    def change(self, value):
        self.changed = value

builtins.str = sstr

def change_the_value(val):
    val.change('After')

val = str('Before')
print (val)
change_the_value(val)
print (val)

What about dataclasses? Also, it allows you to apply type restriction (aka "type hint").

from dataclasses import dataclass

@dataclass
class Holder:
    obj: your_type # Need any type? Use "obj: object" then.

def foo(ref: Holder):
    ref.obj = do_something()

I agree with folks that in most cases you'd better consider not to use it.

And yet, when we're talking about contexts it's worth to know that way.

You can design explicit context class though. When prototyping I prefer dataclasses, just because it's easy to serialize them back and forth.

Cheers!

  1. Python assigns a unique identifier to each object and this identifier can be found by using Python's built-in id() function. It is ready to verify that actual and formal arguments in a function call have the same id value, which indicates that the dummy argument and actual argument refer to the same object.

  2. Note that the actual argument and the corresponding dummy argument are two names referring to the same object. If you re-bind a dummy argument to a new value/object in the function scope, this does not effect the fact that the actual argument still points to the original object because actual argument and dummy argument are two names.

  3. The above two facts can be summarized as “arguments are passed by assignment”. i.e.,

dummy_argument = actual_argument

If you re-bind dummy_argument to a new object in the function body, the actual_argument still refers to the original object. If you use dummy_argument[0] = some_thing, then this will also modify actual_argument[0]. Therefore the effect of “pass by reference” can be achieved by modifying the components/attributes of the object reference passed in. Of course, this requires that the object passed is a mutable object.

  1. To make comparison with other languages, you can say Python passes arguments by value in the same way as C does, where when you pass "by reference" you are actually passing by value the reference (i.e., the pointer)
def i_my_wstring_length(wstring_input:str = "", i_length:int = 0) -> int:
    i_length[0] = len(wstring_input)
    return 0

wstring_test  = "Test message with 32 characters."
i_length_test = [0]
i_my_wstring_length(wstring_test, i_length_test)
print("The string:\n\"{}\"\ncontains {} character(s).".format(wstring_test, *i_length_test))
input("\nPress ENTER key to continue . . . ")

This might be an elegant object oriented solution without this functionality in Python. An even more elegant solution would be to have any class you make subclass from this. Or you could name it "MasterClass". But instead of having a single variable and a single boolean, make them a collection of some kind. I fixed the naming of your instance variables to comply with PEP 8.

class PassByReference:
    def __init__(self, variable, pass_by_reference=True):
        self._variable_original = 'Original'
        self._variable = variable
        self._pass_by_reference = pass_by_reference # False => pass_by_value
        self.change(self.variable)
        print(self)

    def __str__(self):
        print(self.get_variable())

    def get_variable(self):
        if pass_by_reference == True:
            return self._variable
        else:
            return self._variable_original

    def set_variable(self, something):
        self._variable = something

    def change(self, var):
        self.set_variable(var)

def caller_method():

    pbr = PassByReference(variable='Changed') # this will print 'Changed'
    variable = pbr.get_variable() # this will assign value 'Changed'

    pbr2 = PassByReference(variable='Changed', pass_by_reference=False) # this will print 'Original'
    variable2 = pbr2.get_variable() # this will assign value 'Original'
    

I solved a similar requirement as follows:

To implement a member function that changes a variable, dont pass the variable itself, but pass a functools.partial that contains setattr referring to the variable. Calling the functools.partial inside change() will execute settatr and change the actual referenced variable.

Note that setattr needs the name of the variable as string.

class PassByReference(object):
    def __init__(self):
        self.variable = "Original"
        print(self.variable)        
        self.change(partial(setattr,self,"variable"))
        print(self.variable)

    def change(self, setter):
        setter("Changed")

Most of the time, the variable to be passed by reference is a class member. The solution I suggest is to use a decorator to add both a field that is mutable and corresponding property. The field is a class wrapper around the variable.

The @refproperty adds both self._myvar (mutable) and self.myvar property.

@refproperty('myvar')
class T():
    pass

def f(x):
   x.value=6

y=T()
y.myvar=3
f(y._myvar)
print(y.myvar) 

It will print 6.

Compare this to:

class X:
   pass

x=X()
x.myvar=4

def f(y):
    y=6

f(x.myvar)
print(x.myvar) 

In this case, it won't work. It will print 4.

The code is the following:

def refproperty(var,value=None):
    def getp(self):
        return getattr(self,'_'+var).get(self)

    def setp(self,v):
        return getattr(self,'_'+var).set(self,v)

    def decorator(klass):
        orginit=klass.__init__
        setattr(klass,var,property(getp,setp))

        def newinit(self,*args,**kw):
            rv=RefVar(value)
            setattr(self,'_'+var,rv)
            orginit(self,*args,**kw)

        klass.__init__=newinit
        return klass
    return decorator

class RefVar(object):
    def __init__(self, value=None):
        self.value = value
    def get(self,*args):
        return self.value
    def set(self,main, value):
        self.value = value

Simple Answer:

In python like c++, when you create an object instance and pass it as a parameter, no copies of the instance itself get made, so you are referencing the same instance from outside and inside the function and are able to modify the component datums of the same object instance,hence changes are visible to the outside.

For basic types, python and c++ also behave the same to each other, in that copies of the instances are now made, so the outside sees/modifies a different instance than the inside of the function. Hence changes from the inside are not visible on the outside.

Here comes the real difference between python and c++:

c++ has the concept of address pointers, and c++ allows you to pass pointers instead, which bypasses the copying of basic types, so that the inside of the function can affect the same instances as those outside, so that the changes are also visible to the outside. This has no equivalent in python, so is not possible without workarounds (such as creating wrapper types).

Such pointers can be useful in python, but it's not as necessary as it is in c++, because in c++, you can only return a single entity, whereas in python you can return multiple values separated by commas (ie a tuple). So in python, if you have variables a,b, and c, and want a function to modify them persistently (relative to the outside), you would do this:

a=4
b=3
c=8

a,b,c=somefunc(a,b,c)
# a,b,c now have different values here

Such syntax is not easily possible in c++, thus in c++ you would do this instead:

int a=4
int b=3
int c=8
somefunc(&a,&b,&c)
// a,b,c now have different values here

I share another fun way for people to comprehend this topic over a handy tool - VISUALIZE PYTHON CODE EXECUTION based on the example of passing a mutable list from @Mark Ransom

Just play it around, and then you will figure it out.

  1. Passing a String

enter image description here

  1. Passing a List

enter image description here

Related