I wrote this class for testing:
class PassByReference:
def __init__(self):
self.variable = 'Original'
self.change(self.variable)
print(self.variable)
def change(self, var):
var = 'Changed'
When I tried creating an instance, the output was Original
. So it seems like parameters in Python are passed by value. Is that correct? How can I modify the code to get the effect of pass-by-reference, so that the output is Changed
?
Sometimes people are surprised that code like x = 1
, where x
is a parameter name, doesn't impact on the caller's argument, but code like x[0] = 1
does. This happens because item assignment and slice assignment are ways to mutate an existing object, rather than reassign a variable, despite the =
syntax. See Why can a function modify some arguments as perceived by the caller, but not others? for details.
See also What's the difference between passing by reference vs. passing by value? for important, language-agnostic terminology discussion.
Best Answer
Arguments are passed by assignment. The rationale behind this is twofold:
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:
Output:
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:
Output:
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. Thethe_list
was a copy of theouter_list
reference, and we hadthe_list
point to a new list, but there was no way to change whereouter_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
Output:
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. Thethe_string
was a copy of theouter_string
reference, and we hadthe_string
point to a new string, but there was no way to change whereouter_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:
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:
Although this seems a little cumbersome.