Categories
parameter-passing pass-by-reference python reference

How do I pass a variable by reference?

3121

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"

14

  • 28

    For a short explanation/clarification see the first answer to this stackoverflow question. As strings are immutable, they won’t be changed and a new variable will be created, thus the “outer” variable still has the same value.

    – PhilS

    Jun 12, 2009 at 10:35

  • 10

    The code in BlairConrad’s answer is good, but the explanation provided by DavidCournapeau and DarenThomas is correct.

    Jan 7, 2012 at 6:47

  • 76

    Before reading the selected answer, please consider reading this short text Other languages have “variables”, Python has “names”. Think about “names” and “objects” instead of “variables” and “references” and you should avoid a lot of similar problems.

    – lqc

    Nov 15, 2012 at 0:39

  • 2

    another workaround is to create a wrapper ‘reference’ like this: ref = type(”, (), {‘n’:1}) stackoverflow.com/a/1123054/409638

    – robert

    Nov 6, 2014 at 12:01

  • 9

    New official how of Iqc’s link: david.goodger.org/projects/pycon/2007/idiomatic/…

    – Ray Hulha

    Jun 9, 2020 at 19:56

3356

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.

39

  • 194

    Then the same is in C, when you pass “by reference” you’re actually passing by value the reference… Define “by reference” 😛

    Jun 12, 2009 at 11:52

  • 118

    I’m not sure I understand your terms. I’ve been out of the C game for a while, but back when I was in it, there was no “pass by reference” – you could pass things, and it was always pass by value, so whatever was in the parameter list was copied. But sometimes the thing was a pointer, which one could follow to the piece of memory (primitive, array, struct, whatever), but you couldn’t change the pointer that was copied from the outer scope – when you were done with the function, the original pointer still pointed to the same address. C++ introduced references, which behaved differently.

    Jun 12, 2009 at 12:09

  • 41

    @Zac Bowling I don’t really get how what you’re saying is relevant, in a practical sense, to this answer. If a Python newcomer wanted to know about passing by ref/val, then the takeaway from this answer is: 1- You can use the reference that a function receives as its arguments, to modify the ‘outside’ value of a variable, as long as you don’t reassign the parameter to refer to a new object. 2- Assigning to an immutable type will always create a new object, which breaks the reference that you had to the outside variable.

    Sep 8, 2011 at 23:50


  • 14

    @CamJackson, you need a better example – numbers are also immutable objects in Python. Besides, wouldn’t it be true to say that any assignment without subscripting on the left side of the equals will reassign the name to a new object whether it is immutable or not? def Foo(alist): alist = [1,2,3] will not modify the contents of the list from the callers perspective.

    Nov 15, 2011 at 16:46

  • 68

    -1. The code shown is good, the explanation as to how is completely wrong. See the answers by DavidCournapeau or DarenThomas for correct explanations as to why.

    Jan 7, 2012 at 6:41

832

The problem comes from a misunderstanding of what variables are in Python. If you’re used to most traditional languages, you have a mental model of what happens in the following sequence:

a = 1
a = 2

You believe that a is a memory location that stores the value 1, then is updated to store the value 2. That’s not how things work in Python. Rather, a starts as a reference to an object with the value 1, then gets reassigned as a reference to an object with the value 2. Those two objects may continue to coexist even though a doesn’t refer to the first one anymore; in fact they may be shared by any number of other references within the program.

When you call a function with a parameter, a new reference is created that refers to the object passed in. This is separate from the reference that was used in the function call, so there’s no way to update that reference and make it refer to a new object. In your example:

def __init__(self):
    self.variable="Original"
    self.Change(self.variable)

def Change(self, var):
    var="Changed"

self.variable is a reference to the string object 'Original'. When you call Change you create a second reference var to the object. Inside the function you reassign the reference var to a different string object 'Changed', but the reference self.variable is separate and does not change.

The only way around this is to pass a mutable object. Because both references refer to the same object, any changes to the object are reflected in both places.

def __init__(self):         
    self.variable = ['Original']
    self.Change(self.variable)

def Change(self, var):
    var[0] = 'Changed'

19

  • 123

    Good succinct explanation. Your paragraph “When you call a function…” is one of the best explanations I’ve heard of the rather cryptic phrase that ‘Python function parameters are references, passed by value.’ I think if you understand that paragraph alone, everything else kind of just makes sense and flows as a logical conclusion from there. Then you just have to be aware of when you’re creating a new object and when you’re modifying an existing one.

    Nov 16, 2011 at 0:03


  • 4

    But how can you reassign the reference? I thought you can’t change the address of ‘var’ but that your string “Changed” was now going to be stored in the ‘var’ memory address. Your description makes it seem like “Changed” and “Original” belong to different places in memory instead and you just switch ‘var’ to a different address. Is that correct?

    – Kashif

    May 7, 2012 at 1:10


  • 11

    @Glassjawed, I think you’re getting it. “Changed” and “Original” are two different string objects at different memory addresses and ‘var’ changes from pointing to one to pointing to the other.

    May 7, 2012 at 1:46

  • 2

    @TonySuffolk66 id gives the identity of the object referenced, not the reference itself.

    Mar 10, 2018 at 14:24

  • 1

    @MinhTran in the simplest terms, a reference is something that “refers” to an object. The physical representation of that is most likely a pointer, but that’s simply an implementation detail. It really is an abstract notion at heart.

    Oct 20, 2018 at 4:21

432

I found the other answers rather long and complicated, so I created this simple diagram to explain the way Python treats variables and parameters.
enter image description here

10

  • 4

    lovely, makes it easy to spot the subtle diff that there is an intermediate assignment, not obvious to a casual onlooker. +1

    – user22866

    Jan 3, 2016 at 15:02

  • 11

    It doesn’t matter if A is mutable or not. If you assign something different to B, A doesn’t change. If an object is mutable, you can mutate it, sure. But that has nothing to do with assignment directly to a name..

    – Martijn Pieters

    May 25, 2016 at 0:06

  • 2

    @Martijn You’re right. I removed the part of the answer that mentions mutability. I don’t think it can get any simpler now.

    – Zenadix

    May 25, 2016 at 16:19

  • 8

    Thanks for the update, much better! What confuses most people is assignment to a subscription; e.g. B[0] = 2, vs. direct assignment, B = 2.

    – Martijn Pieters

    May 25, 2016 at 16:32

  • 13

    “A is assigned to B.” Is that not ambiguous? I think in ordinary English that can mean either A=B or B=A.

    Jul 4, 2016 at 23:06