3259

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.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
David Sykes
  • 48,469
  • 17
  • 71
  • 80
  • 11
    The code in BlairConrad's answer is good, but the explanation provided by DavidCournapeau and DarenThomas is correct. – Ethan Furman Jan 07 '12 at 06:47
  • 79
    Before reading the selected answer, please consider reading this short text [Other languages have "variables", Python has "names"](http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables). Think about "names" and "objects" instead of "variables" and "references" and you should avoid a lot of similar problems. – lqc Nov 15 '12 at 00:39
  • 32
    For a short explanation/clarification see the first answer to [this stackoverflow question](http://stackoverflow.com/questions/534375/passing-values-in-python). 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 '09 at 10:35
  • 2
    another workaround is to create a wrapper 'reference' like this: ref = type('', (), {'n':1}) http://stackoverflow.com/a/1123054/409638 – robert Nov 06 '14 at 12:01
  • 1
    For global names, pass by reference can be simulated by passing the name as a string and using globals(). `def change(s): globals()[s] = 'changed'` followed by `a = 'orig'; change('a'); print(a)` prints `'changed'`. – Terry Jan Reedy Feb 02 '16 at 23:28
  • Some immutable types: {int, float, long, complex, str, bytes, tuple, frozen set} Some mutable types: {byte array, list, set, dict} – MrRolling Jul 26 '16 at 04:42
  • 1
    Python has variables. There's no conceptual problem with this term at all, and it is in common use. – Elazar Sep 04 '16 at 23:01
  • [jeff Knupp's blog](https://jeffknupp.com/blog/2012/11/13/is-python-callbyvalue-or-callbyreference-neither/) and [stupidpythonideas](http://stupidpythonideas.blogspot.in/2013/11/does-python-pass-by-value-or-by.html) are some good explanations for this. – akki May 19 '17 at 11:28
  • For the dataframe named 'bob' (from a string variable, and that's the tricky part), give me its current contents. Should be easy. Sadly I'm not getting it. – gseattle Oct 21 '19 at 19:27
  • 3
    Working link: [Other languages have "variables", Python has "names"](https://web.archive.org/web/20180411011411/http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables) – Abraham Sangha Apr 22 '20 at 23:30
  • 11
    New official how of Iqc's link: https://david.goodger.org/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables – Ray Hulha Jun 09 '20 at 19:56
  • I come from C# & am trying to understand the question better. In Python everything is an object and objects can be mutable or immutable. The code here uses "string" which is an immutable object and attempting to change it within function scope is not going to change caller's value (behaves like pass-by-value) & if the code used a mutable custom class object - changing within function scope will change the caller's value (behaves like pass-by-ref). You'll see the exact same end result in C# (but the way it achieves is pass-by-value/ref). So isn't the net effect same? so isn't the question moot? – Naren Mar 27 '21 at 12:48
  • @PeterR because OOP > 70s programming without classes and objects. It's just easier to write and understand programs when it's object-oriented. I think everything in the Universe can be represented as an object, even non-existing in real life programming concepts. – KulaGGin Apr 29 '21 at 17:24
  • 1
    @Naren no, it *doesn't behave like either call by reference or call by value*. Assignment to a parameter, regardless of the type used, will **never** be seen in the caller, therefore it is not call by reference. Similarly, objects *are not copied*, again, regardless of the type used, when they are passed in to a function, that is why mutator methods will affect those objects everywhere they are referenced. – juanpa.arrivillaga Jan 24 '22 at 17:44
  • The original version of this question said something about the documentation being unclear on this point. I wish I knew what part of the documentation was being referenced, exactly. The documentation for 2.6 includes [a detailed section on this exact topic](https://docs.python.org/2.6/faq/programming.html#how-do-i-write-a-function-with-output-parameters-call-by-reference), but I can't tell for sure when it was added. – Karl Knechtel Jan 13 '23 at 00:31

40 Answers40

3495

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.

random_user
  • 820
  • 1
  • 7
  • 18
Blair Conrad
  • 233,004
  • 25
  • 132
  • 111
  • 205
    Then the same is in C, when you pass "by reference" you're actually passing _by value_ the reference... Define "by reference" :P – Andrea Ambu Jun 12 '09 at 11:52
  • 123
    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. – Blair Conrad Jun 12 '09 at 12:09
  • 4
    @andrea, not it is not like C at all. Conrad is correct, but the terms reference/values are confusing in python. That's why you should really use another term (see my link to effbot for a good explanation) – David Cournapeau Jun 12 '09 at 14:41
  • 6
    bring up mutability is just adding confusion. it actually doesn't have anything to with the issue. you state it correct at first in that you can change the reference for something not in your scope (like a pointer pointer). – Zac Bowling Dec 22 '10 at 02:46
  • 6
    @Zac Bowling Mutability is totally relevant. If strings were mutable, then the first string example would have a different output. It's important to know that setting the value of a passed-in string will create a new string object, not modify the passed one. Mutability is what prevents a string argument from behaving the same as say, an integer argument in this case. – Cam Jackson Sep 06 '11 at 02:30
  • 6
    @Cam Jackson actually it's not relevant. Passing by reference means giving the ability to change the pointer that the calling reference was using. Talking about changing the data the destination of that pointer adds confusion and just an implementation detail. – Zac Bowling Sep 08 '11 at 17:54
  • 45
    @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. – Cam Jackson Sep 08 '11 at 23:50
  • 16
    @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. – Mark Ransom Nov 15 '11 at 16:46
  • 8
    @BlairConrad, passing "by reference" in C is just a commonly recognized convention whereby you pass the pointer to something rather than the value of something. In that respect it behaves exactly like Python: you may update the value pointed to by the pointer but updating the pointer itself has no effect outside the function, since the pointer was passed by value. – Mark Ransom Nov 15 '11 at 16:54
  • Cue the `sys._getframe(1).f_locals['new_string'] = 'foo'` hack. Or just using ctypes.. :) – John Doe Dec 11 '11 at 19:28
  • 73
    -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. – Ethan Furman Jan 07 '12 at 06:41
  • "..., 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." This is wrong or at least not relevant - you can never rebind a reference. – Johan Lundberg Jan 30 '12 at 20:52
  • 7
    Oh, that's sad. "It's passed by value, but the value is a reference". Sigh. Well, *everything* is a value. When the value is a reference, that's pass by reference. The difference in Python is minimal as Pythons variables aren't like C's variables, but calling it pass by value is definitely incorrect. – Lennart Regebro May 03 '13 at 08:10
  • 3
    I down voted because the code(where you do assignment in function body) given for string and list is basically the same and has the same behavior. And list is mutable a string is not. Your answer did not cleared a thing for me. It just made me realize that I totally don't understand Python. – tom Jun 11 '13 at 23:17
  • 9
    @Lennart Regebro, just because the value is a reference to something doesn't make it pass by reference. In C++ you can actually pass by reference, and when you do, if you reassign the reference, the parameter you passed will actually be modified. In Python, if you try to reassign the parameter you will just be changing the mapping of the name in the namespace of your function, something which is fundamentally different. Still, the whole idea of pass by reference is so screwed up now because everyone is using it to describe a different thing. – Richard Fung Nov 17 '13 at 18:31
  • 2
    @Synderesis: *"In C++"...* - Well, yeah, but now we are talking about Python. Python is passing references. Since it is passing reference, that's reasonably "pass by reference". *"In Python, if you try to reassign the parameter"* - Yes, but that's a completely different issue. This is because Python doesn't have variables that point to a memory location like C/C++. It has objects, and variables are names for these objects. – Lennart Regebro Nov 17 '13 at 19:24
  • 3
    @Lennart Regebro: I realize that, but in the end you could also consider Python to be pass by value with the values being references. Of course, that is why I added that last line anyway. Defining terms to mean different things for different languages is by all means useless, because the whole point of defining those terms is to make it clear what you are saying. – Richard Fung Nov 29 '13 at 22:26
  • 3
    This answer is hence factually incorrect, and have been upvotes as "thanks" by newbies who don't understand the internals of Python. Which is why it makes me sad. – Lennart Regebro Nov 30 '13 at 08:55
  • 3
    @Lennart Regebro "it is a reference passed as a value the type is a reference/pointer and you would have to dereference it to access it." I don't see how that is true. Java uses references but is pass by value, and behaves identically to Python in that it has objects and variables are names referencing these objects. The statement you made earlier "When the value is a reference, that's pass by reference." is incorrect, because if it's pass by value, you can reassign the reference. However, in pass by reference, if you try to reassign the variable you are actually modifying it. – Richard Fung Dec 05 '13 at 20:11
  • 3
    @Synderesis: Once again, then: http://effbot.org/zone/call-by-object.htm See Davids answer. With your definition of pass-by-value, then EVERYTHING IS PASS BY VALUE. There exists no pass-by-reference with that wording of it, since pass-by-reference is when the value you pass is a reference, but you don't have to treat the value as a reference inside the function. What Java calls "pass-by-value, and the value is a reference" is **exactly what pass-by-reference is.** The whole point is that what Python **and Java** does ***does not exactly fit either concept as used in other languages***. – Lennart Regebro Dec 05 '13 at 20:27
  • 3
    @Lennart Regebro "There exists no pass-by-reference with that wording of it, since pass-by-reference is when the value you pass is a reference" In C++ you can have true pass by reference. Java is pass by value: http://stackoverflow.com/questions/40480/is-java-pass-by-reference – Richard Fung Dec 08 '13 at 10:42
  • @Synderesis: I wish the "move this to chat" option was always available, coomments are really not the place for me to repeat the same thing over and over. – Lennart Regebro Dec 08 '13 at 13:01
  • 4
    _"...parameter passed in..."_ is incorrect use of terminology. A [parameter](http://docs.python.org/3/glossary.html#term-parameter) is a named entity in a function (or method) definition that specifies an argument (or in some cases, arguments) that the function can accept. An [argument](http://docs.python.org/3/glossary.html#term-argument) is a value passed to a function (or method) when calling the function. – Honest Abe Feb 10 '14 at 23:47
  • Unless you look at `locals()` etc., this is exactly like Java. In Java the address-space of references is an implementation detail, but in Python is a string in some scope (`__dict__`). In C it would be numbers in a global scope. Also, there is only one type of primitive in Python (reference to object) and several primitives in Java, one of which is reference to Object. Pass-by-reference in Python would mean "pass the scope and the name of the variable" but currently there is no such thing. it can be done explicitly - and it is, when emulating this mechanism using a class (which is a scope). – Elazar Sep 04 '16 at 22:58
  • I've most often seen the term "call-by-object-reference" not "by assignment" – Tommy Sep 07 '16 at 18:52
  • As a means to pass a reference to a name, why not pass the name itself as a string? Then use `eval(name)` to get the current object that the name references. – Bill Dec 31 '16 at 22:47
  • https://jeffknupp.com/blog/2012/11/13/is-python-callbyvalue-or-callbyreference-neither/ http://stupidpythonideas.blogspot.in/2013/11/does-python-pass-by-value-or-by.html ^These are also some nice explanations. – akki May 19 '17 at 11:26
  • "but if you rebind the reference in the method, the outer scope will know nothing about it", well the if the passed reference is mutable and you performed some operations (let say appended some values to the list) then these operations will be visible by the outer scope. The outer-scope will stop seeing changes only once the rebind is performed. All the previous operations do affect the original object. – rkachach Aug 30 '17 at 17:31
  • 1
    @EthanFurman You are wrong. Even if you read the link in DavidCournapeau's answer that is [Call By Object](http://effbot.org/zone/call-by-object.htm), you will see that all of the expressions “call by object”, “call by sharing“ or “call by object reference“, have the same meaning that is using an address to access the object. And for sure the address has to be determined from namespace. I can't accept that "Call by object reference" is different from "Call by reference". – Happy Ahmad Jul 09 '18 at 09:21
  • @BlairConrad "The parameter passed in is actually a reference to an object (but the reference is passed by value)". This sounds similar to pass by reference. How is pass by reference and assignment different? Can you give an example to explain "pass by assignment"? – GeorgeOfTheRF Aug 03 '18 at 08:44
  • 2
    @ML_Pro, "pass by assignment" seems to be a term made up by the Python documenters to describe "pass by value". For the user, I see no functional difference between passing a value that is a reference (or handle) as happens in languages such as Java or C# and what Python does, and I'd never use the term "pass by assignment"; it was edited into the answer, I assume to align with the documentation. – Blair Conrad Aug 04 '18 at 09:57
  • Okay, so when you pass a list reference variable into the method, you're actually giving it a "copy" of the list reference. That's why changing what the "list reference copy" is pointing to doesn't change what the "original list reference" is pointing to. – NoName Oct 09 '19 at 23:13
  • 3
    @HappyAhmad it absolutely *is* different to call by reference. If Python supported call by reference, you could do something like `def foo(&var): var = 2` then `x = 0; y = 1; foo(x); foo(y)` then `print(x, y)` would print `2 2` – juanpa.arrivillaga Mar 13 '21 at 19:58
  • 2
    @BlairConrad because that is simply confusing the implementation for the semantics. It isn't pass by value because the value isn't copied. The *value is the object*, python doesn't support reference types like pointers. The fact that CPython uses pointers is irrelevant, I could write a Python interpreter in Fortran using only call by reference internally, and that wouldn't make Python call by reference. Yes, "pass by assignment" is a Pythonism, but academically, it is known as [call by sharing](https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sharing) – juanpa.arrivillaga Mar 13 '21 at 20:00
  • 1
    @NoName **no**. That isn't how it works at all. Assignment doesn't work like in C/C++. An assignment statement merely changes what a name refers to in a namespace. Often, it is *literally* just chaning the value of a key in a dict (global namespaces and module namespaces are implemented as python `dict` objects) – juanpa.arrivillaga Mar 13 '21 at 20:00
  • Confusing language used on lists passed into the two functions. In both cases, the list is passed by reference, however, in the first case, the list is modified so changes are visible outside the function. On the other hand, in the second case, a new list is assigned to the passed parameter, so it makes a new list without making changes to the list passed to the function. That's why changes are not visible outside the function – Muhammad Zubair Oct 18 '21 at 14:52
  • 1
    @MuhammadZubair no, **in neither case is pass by reference occurring**. These terms have well understood meanings in programming languages, and Python *never supports call by reference*. If it *were* pass by reference, and a new list were assigned to the parameter, that change would be *visible in the caller*. That is a key feature of pass-by-reference. You've essentially proven your own point incorrect.\ – juanpa.arrivillaga Dec 20 '21 at 06:51
  • Good explanation. The confusing part for me (as C++) developer is that a function can change the contents ('pass by reference') but it depends on the argument passed in. – gast128 Jan 11 '22 at 10:40
  • @gast128 C++'s references implement actual pass-by-reference. "The reference" itself is not an object in C++; it isn't required to have storage and you aren't allowed to take its address (attempting to gives you the address of the reference). However, C++ variables have value *semantics*, whereas Python's have *reference semantics* (in C++ terms, everything is implicitly indirected once). A value passing from an argument to a parameter in Python works **the same way** that assigning to a new name works **in Python**, which **is not** the way it works in C++. – Karl Knechtel Jul 12 '23 at 16:31
  • The indirection that Python automatically uses for everything is the same reason that, for example, it can natively and effortlessly support heterogeneous lists (the underlying storage for the list object just contains pointers, so the size of the underlying storage for the elements doesn't matter). – Karl Knechtel Jul 12 '23 at 16:33
882

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'
random_user
  • 820
  • 1
  • 7
  • 18
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • 130
    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. – Cam Jackson Nov 16 '11 at 00: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 07 '12 at 01: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. – Mark Ransom May 07 '12 at 01:46
  • using the id() function helps clarify matters, because it makes it clear when Python creates a new object (so I think, anyway). – Tim Richardson Nov 11 '15 at 10:07
  • Woah... so it makes sense that lists are mutable because one can imagine saying "ok python, make these boxes for me"... then the contents of the boxes can be modified. **But** things like strings and numbers can without complication point to a series of 1s and 0s in your memory, so it makes more sense to "tag" them with names. – Luke Davis Jan 10 '17 at 02:37
  • This answer and [this blog post by effbot on python-objects](http://effbot.org/zone/python-objects.htm) together make things as clear as they can be. – akki Mar 06 '17 at 07:09
  • 2
    Function calls do not create new references - use the id function inside and outside of the function to confirm that. The difference is what happens to the object when you attempt to change it inside the function. – Tony Suffolk 66 Mar 10 '18 at 10:55
  • 4
    @TonySuffolk66 `id` gives the identity of the object referenced, not the reference itself. – Mark Ransom Mar 10 '18 at 14:24
  • Mark - I took your use of reference to mean a object; when a function is called a new binding is created of an existing object to a new name (with a increase in the Ref count). Most documentation I have seen talks about this as a new binding, and not a new reference. Apologies for misunderstanding. – Tony Suffolk 66 Mar 11 '18 at 13:53
  • @TonySuffolk66 I come from a C++ background, so I might be a little loose on the terminology. A C++ reference is the closest thing to a Python variable. – Mark Ransom Mar 11 '18 at 21:31
  • @MarkRansom - strictly speaking Python doesn't have 'variables' - well not in a C/C++ way of having a memory location which is known by that name. What Python has is one or more names which are bound to a reference to object - or sometime a name is bound to a container of object references. Oh the joys of terminology :-) – Tony Suffolk 66 Mar 13 '18 at 07:30
  • So, can we say that a mutable object is passed by reference and an immutable object is not ? – Yasir Jan Sep 30 '18 at 09:55
  • @YasirJan no, they're both passed by reference. It's just that for an immutable object the reference doesn't help you. – Mark Ransom Sep 30 '18 at 16:10
  • @MarkRansom What exactly is a `reference`? Your definition doesn't go beyond suggesting that it is "something" that points/refers to an object (which is a helpful definition to aid in describing what a reference `does` but not necessarily what it *is*). – Minh Tran Oct 20 '18 at 03:38
  • 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. – Mark Ransom Oct 20 '18 at 04:21
  • One should perhaps note that in the second example (mutable object), you cannot update the reference either: var = ['Changed'] won't have the desired effect. WIth var[0] = 'Changed', the object identity is the same; we just use the object's interface to make changes to it. It would be interesting to have a notation like var[] = ... that updates the actual reference (replaces the object as a whole). – marc_r Nov 07 '21 at 14:43
  • @marc_r I thought that was obvious from the way I explained the mechanics. Mutating a list isn't a real answer to the question, it's just a workaround - the closest thing that Python allows. – Mark Ransom Nov 07 '21 at 20:14
  • Okay, so everything is a reference under the hood. So, how does python determine when to create a new object and when to refer to an already existing one? – James M. Lay Jun 16 '23 at 05:53
  • 1
    @JamesM.Lay some operations, such ass assigning to a list slice or dictionary key, are just defined that way. They're generally secretly converted to function calls such as `__setitem__`. – Mark Ransom Jun 16 '23 at 12:29
  • @MarkRansom your answer is consistent with the one I got from a certain popular chat engine. Basically, it's the operation that defines the creation-of or reference-to objects. Addition, for example, always creates a new object. – James M. Lay Jun 19 '23 at 06:12
  • @JamesM.Lay even that may depend on whether the object is mutable or not. I haven't tested it but I think addition in `numpy` might work different. – Mark Ransom Jun 19 '23 at 16:13
  • @MarkRansom that's right, I forgot to consider operator overloading. Yikes. – James M. Lay Jun 20 '23 at 18:36
455

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

Zenadix
  • 15,291
  • 4
  • 26
  • 41
  • 9
    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 '16 at 16:32
  • 14
    "A is assigned to B." Is that not ambiguous? I think in ordinary English that can mean either `A=B` or `B=A`. – Hatshepsut Jul 04 '16 at 23:06
  • I do like the visual representation, but still misses the point of `mutable` vs `immutable` which makes the right leg moot since there will be no `append` available. (still got an upvote for the visual rep though) :) – Madivad Jul 19 '16 at 12:40
  • What do you mean by B is modified in-place?B is not an object – Abhinav Oct 20 '19 at 03:57
  • @Abhinav in Python, EVERYTHING is an object - even simple integers. But some objects can be modified (mutable) and some can't. If the object has an `append` method then it must be mutable. – Mark Ransom Mar 24 '21 at 16:00
  • This is a great answer that illustrates a key core concept of Python, but I think somewhere along the way you lost the connection to the original question. – Mark Ransom Mar 24 '21 at 16:05
  • "Something else is assigned to B" should be "B is assigned to something else". Names are assigned to values, not the other way around. Names refer to values, values don't know what names they have. – timgeb Feb 28 '22 at 09:11
  • At this level of simplicity, I don't see how the diagram is helpful vs. a plain-text explanation. – Karl Knechtel Jan 13 '23 at 00:33
274

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

Call By Object

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
David Cournapeau
  • 78,318
  • 8
  • 63
  • 70
  • 25
    I find it hard to buy. To me is just as Java, the parameters are pointers to objects in memory, and those pointers are passed via the stack, or registers. – Luciano Dec 13 '11 at 01:25
  • 10
    This is not like java. One of the case where it is not the same is immutable objects. Think about the trivial function lambda x: x. Apply this for x = [1, 2, 3] and x = (1, 2, 3). In the first case, the returned value will be a copy of the input, and identical in the second case. – David Cournapeau Dec 14 '11 at 01:53
  • 34
    No, it's *exactly* like Java's semantics for objects. I'm not sure what you mean by "In the first case, the returned value will be a copy of the input, and identical in the second case." but that statement seems to be plainly incorrect. – Mike Graham Nov 14 '12 at 20:58
  • 4
    My comment is indeed incorrect, but I stand on the fact that python semantics are different from java, as explained in the referred article. In python, whether changes within a function are visible outside it for its argument depends on the mutability, not on being a special type (say object vs primitive types in java), and the argument passing 'protocol' is the same for everything in python. – David Cournapeau Nov 16 '12 at 06:34
  • 28
    It is exactly the same as in Java. Object references are passed by value. Anyone who thinks differently should attach the Python code for a `swap` function that can swap two references, like this: `a = [42] ; b = 'Hello'; swap(a, b) # Now a is 'Hello', b is [42]` – cayhorstmann Dec 20 '12 at 03:42
  • 5
    Whether something is an object or not is irrelevant (especially since almost everything is an object in python, e.g. int, float, etc...). The mutability matters. You can write a swap function that would work for lists (mutable), but not for tuples or strings (immutable). See also this: http://www.python-course.eu/passing_arguments.php, which clearly shows a different behavior than java in some cases. – David Cournapeau Dec 21 '12 at 10:00
  • 28
    It is exactly the same as Java when you pass objects in Java. However, Java also have primitives, which are passed by copying the value of the primitive. Thus they differ in that case. – Claudiu Jul 17 '13 at 18:59
  • @Claudiu: Its not only in the case of Java primitives, any immutable object in Java will behave same as primitives such as String which is a Java object – brain storm Jul 14 '14 at 23:29
  • 3
    @Claudiu you are 100% right, except Java does not differ with the _behavior_ of the additional primitives - it merely _does_ have additional primitives, where Python don't. Other differences are visible when you look at `locals()` and some other meta-stuff - the scopes are implemented in a different way, and this implementation detail is visible in Python. – Elazar Sep 04 '16 at 23:09
  • 1
    It's literally pass by reference, as what is being passed is the address. Passing the number 1 passes the address of the object with value 1 to the function argument by assignment. The thing is that even if it is passed by reference, 1 is an integer which is immutable and hence you will never be able to change it. – MattSt Jul 30 '22 at 19:07
223

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.

MurugananthamS
  • 2,395
  • 4
  • 20
  • 49
Daren Thomas
  • 67,947
  • 40
  • 154
  • 200
  • 11
    At first glance this answer seems to sidestep the original question. After a second read I've come to realize that this makes the matter quite clear. A good follow up to this "name assignment" concept may be found here: [Code Like a Pythonista: Idiomatic Python](http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables) – Christian Groleau Nov 22 '17 at 21:45
102

There are no variables in Python

The key to understanding parameter passing is to stop thinking about "variables". There are names and objects in Python and together they appear like variables, but it is useful to always distinguish the three.

  1. Python has names and objects.
  2. Assignment binds a name to an object.
  3. Passing an argument into a function also binds a name (the parameter name of the function) to an object.

That is all there is to it. Mutability is irrelevant to this question.

Example:

a = 1

This binds the name a to an object of type integer that holds the value 1.

b = x

This binds the name b to the same object that the name x is currently bound to. Afterward, the name b has nothing to do with the name x anymore.

See sections 3.1 and 4.2 in the Python 3 language reference.

How to read the example in the question

In the code shown in the question, the statement self.Change(self.variable) binds the name var (in the scope of function Change) to the object that holds the value 'Original' and the assignment var = 'Changed' (in the body of function Change) assigns that same name again: to some other object (that happens to hold a string as well but could have been something else entirely).

How to pass by reference

So if the thing you want to change is a mutable object, there is no problem, as everything is effectively passed by reference.

If it is an immutable object (e.g. a bool, number, string), the way to go is to wrap it in a mutable object.
The quick-and-dirty solution for this is a one-element list (instead of self.variable, pass [self.variable] and in the function modify var[0]).
The more pythonic approach would be to introduce a trivial, one-attribute class. The function receives an instance of the class and manipulates the attribute.

faressalem
  • 574
  • 6
  • 20
Lutz Prechelt
  • 36,608
  • 11
  • 63
  • 88
  • 50
    "Python has no variables" is a silly and confusing slogan, and I really wish people would stop saying it... :( The rest of this answer is good! – Ned Batchelder Jun 23 '14 at 21:53
  • 23
    It may be shocking, but it is not silly. And I don't think it is confusing either: It hopefully opens up the recipient's mind for the explanation that is coming and puts her in a useful "I wonder what they have instead of variables" attitude. (Yes, your mileage may vary.) – Lutz Prechelt Jun 25 '14 at 07:30
  • 25
    would you also say that Javascript has no variables? They work the same as Python's. Also, Java, Ruby, PHP, .... I think a better teaching technique is, "Python's variables work differently than C's." – Ned Batchelder Jun 25 '14 at 11:09
  • 13
    Yes, Java has variables. So does Python, and JavaScript, Ruby, PHP, etc. You wouldn't say in Java that `int` declares a variable, but `Integer` does not. They both declare variables. The `Integer` variable is an object, the `int` variable is a primitive. As an example, you demonstrated how your variables work by showing `a = 1; b = a; a++ # doesn't modify b`. That's exactly true in Python also (using `+= 1` since there is no `++` in Python)! – Ned Batchelder Oct 29 '14 at 16:29
  • 7
    The concept of "variable" is complex and often vague: **A variable is a container for a value, identified by a name.** In Python, the values are objects, the containers are objects (see the problem?) and the names are actually separate things. I believe it is much tougher to get an _accurate_ understanding of variables in this manner. The names-and-objects explanation appears more difficult, but is actually simpler. – Lutz Prechelt Oct 09 '15 at 10:51
  • 3
    I really don't see how this answer could be helpful in light of the question. No solution is given, only the status quo of python is recited. How can you pass an argument, so that it can be changed? Most of the answers here don't give a solution. But this one, denies the existence of the obvious in the first lines, so it stands out of the pack. Sorry for the downvote, but it just made me a bit mad. – Sherlock70 Jun 14 '16 at 12:31
  • 1
    *var·i·a·ble ˈverēəb(ə)l/Submit adjective 1. not consistent or having a fixed pattern; liable to change.* I would argue that python does have "Variables" – Erich Aug 24 '17 at 20:44
  • "That is all there is to it. Mutability is irrelevant for this question." yes it does. If the self.variable were mutable then it could be changed inside the function self.change(). Thus, passing an immutable type as parameter function will never affect the passed "variable". – rkachach Aug 30 '17 at 17:40
  • I like this answer. To further the idea of "variables" vs "names" (emphasis on the quotes) may be found here: [Code Like a Pythonista: Idiomatic Python](http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables) – Christian Groleau Nov 22 '17 at 21:43
  • "Assignment binds a name to an object." - this is why properties must be deleted from python, because 'obj.some_prop = val' does some hidden non-obvious logic instead of binding object to name. – iperov Feb 24 '22 at 09:23
  • @iperov Why? `some_prop` is a perfectly fine name like any other. No problem and nothing non-obvious there at all. (Except maybe that there is more than a single [namespace](https://docs.python.org/3/glossary.html#term-namespace) in Python and the question and answer do not talk about that aspect.) – Lutz Prechelt Mar 09 '22 at 09:03
  • @Lutz Prechelt it is not clear to those who have not designed complex architectures. Any non-obvious thing to the "external user of a class" is a pitfall, or a shot in the leg. – iperov Mar 09 '22 at 09:15
  • 1
    The last section gives the false impression that passing `[self.variable]` and modifying `var[0]` will modify `self.variable`, which will never happen. One way this could work would be to store `['Original']` instead of `'Original'`, modify `var[0]` as suggested, and then print `self.variable[0]` instead of `self.variable`. – sam hocevar Jan 13 '23 at 10:52
86

Effbot (aka Fredrik Lundh) has described Python's variable passing style as call-by-object: http://effbot.org/zone/call-by-object.htm

Objects are allocated on the heap and pointers to them can be passed around anywhere.

  • When you make an assignment such as x = 1000, a dictionary entry is created that maps the string "x" in the current namespace to a pointer to the integer object containing one thousand.

  • When you update "x" with x = 2000, a new integer object is created and the dictionary is updated to point at the new object. The old one thousand object is unchanged (and may or may not be alive depending on whether anything else refers to the object).

  • When you do a new assignment such as y = x, a new dictionary entry "y" is created that points to the same object as the entry for "x".

  • Objects like strings and integers are immutable. This simply means that there are no methods that can change the object after it has been created. For example, once the integer object one-thousand is created, it will never change. Math is done by creating new integer objects.

  • Objects like lists are mutable. This means that the contents of the object can be changed by anything pointing to the object. For example, x = []; y = x; x.append(10); print y will print [10]. The empty list was created. Both "x" and "y" point to the same list. The append method mutates (updates) the list object (like adding a record to a database) and the result is visible to both "x" and "y" (just as a database update would be visible to every connection to that database).

Hope that clarifies the issue for you.

Raymond Hettinger
  • 216,523
  • 63
  • 388
  • 485
  • 6
    I really appreciate learning about this from a developer. Is it true that the `id()` function returns the pointer's (object reference's) value, as pepr's answer suggests? – Honest Abe Jan 13 '14 at 22:21
  • 6
    @HonestAbe Yes, in CPython the *id()* returns the address. But in other pythons such as PyPy and Jython, the *id()* is just a unique object identifier. – Raymond Hettinger Jan 14 '14 at 09:03
  • The dictionary is a reasonable mental model, and pretty accurate for 2.x; but in 3.x, *local* variables have optimized storage that doesn't work like a dictionary, and the `locals()` function needs to create a `dict` on the fly. – Karl Knechtel Jul 12 '23 at 16:36
68

Technically, Python always uses pass by reference values. I am going to repeat my other answer to support my statement.

Python always uses pass-by-reference values. There isn't any exception. Any variable assignment means copying the reference value. No exception. Any variable is the name bound to the reference value. Always.

You can think about a reference value as the address of the target object. The address is automatically dereferenced when used. This way, working with the reference value, it seems you work directly with the target object. But there always is a reference in between, one step more to jump to the target.

Here is the example that proves that Python uses passing by reference:

Illustrated example of passing the argument

If the argument was passed by value, the outer lst could not be modified. The green are the target objects (the black is the value stored inside, the red is the object type), the yellow is the memory with the reference value inside -- drawn as the arrow. The blue solid arrow is the reference value that was passed to the function (via the dashed blue arrow path). The ugly dark yellow is the internal dictionary. (It actually could be drawn also as a green ellipse. The colour and the shape only says it is internal.)

You can use the id() built-in function to learn what the reference value is (that is, the address of the target object).

In compiled languages, a variable is a memory space that is able to capture the value of the type. In Python, a variable is a name (captured internally as a string) bound to the reference variable that holds the reference value to the target object. The name of the variable is the key in the internal dictionary, the value part of that dictionary item stores the reference value to the target.

Reference values are hidden in Python. There isn't any explicit user type for storing the reference value. However, you can use a list element (or element in any other suitable container type) as the reference variable, because all containers do store the elements also as references to the target objects. In other words, elements are actually not contained inside the container -- only the references to elements are.

Community
  • 1
  • 1
pepr
  • 20,112
  • 15
  • 76
  • 139
  • 45
    Inventing new terminology (such as "pass by reference value" or "call by object" is not helpful). "Call by (value|reference|name)" are standard terms. "reference" is a standard term. Passing references by value accurately describes the behavior of Python, Java, and a host of other languages, using standard terminology. – cayhorstmann Dec 20 '12 at 03:54
  • 6
    @cayhorstmann: The problem is that *Python variable* has not the same terminology meaning as in other languages. This way, *call by reference* does not fit well here. Also, how do you *exactly* define the term *reference*? Informally, the Python way could be easily described as passing the address of the object. But it does not fit with a potentially distributed implementation of Python. – pepr Dec 20 '12 at 08:54
  • 1
    I like this answer, but you might consider if the example is really helping or hurting the flow. Also, if you replaced 'reference value' with 'object reference' you would be using terminology that we could consider 'official', as seen here: [Defining Functions](http://docs.python.org/3.3/tutorial/controlflow.html#defining-functions) – Honest Abe Jan 13 '14 at 22:10
  • 1
    Well, but the official says... "*arguments are passed using **call by value** (where the **value** is always an object **reference**, not the value of the object).*" This way, you may be tempted to substitute it textually as ... *arguments are passed using **call by reference***, which is a bit confusing beacuse it is not true. The confusion is caused by a bit more complex situation where none of the classical terms fits perfectly. I did not find any simpler example that would illustrate the behaviour. – pepr Jan 14 '14 at 23:31
  • 2
    There is a footnote indicated at the end of that quote, which reads: _"Actually, **call by object reference** would be a better description, since if a mutable object is passed, the caller will see any changes the callee makes to it..."_ I agree with you that confusion is caused by trying to fit terminology established with other languages. Semantics aside, the things that need to be understood are: dictionaries / namespaces, [name binding operations](http://docs.python.org/3.3/reference/executionmodel.html) and the relationship of name→pointer→object (as you already know). – Honest Abe Jan 16 '14 at 06:28
  • 1
    This answer is at best misleading, and at worst outright false. – Myridium Aug 28 '20 at 04:54
  • 1
    @pepr - it may technically correct (I cannot understand 50% of it) but it offers no clarification to a beginner who is trying to fit the behaviour of python into a conceptual model where something is either passed by reference or passed by value. This is a pragmatic question, let alone a theoretical one. The answer is that Python 'passes by assignment', behaving differently for mutable and immutable types. I was surprised to learn that `id(x)` is the same as what was passed in, because assigning a new value to the parameter has a different result than assigning a value to the `x` before input. – Myridium Aug 31 '20 at 04:58
  • 1
    The example given leads the reader to believe Python behaves one way, and yet if you give the example of an integer (immutable type) it will appear to behave the other way! How is the mutable type behaviour reconciled with your assertion that everything is passed by reference, and with the fact that `id` is preserved? This needs to be explained. – Myridium Aug 31 '20 at 05:07
  • @Myridium: Python does not use the pass by value (as compiled languages do). It always passes the address (the id) of the target object. Of course, if the object is mutable, its content can be changed by assigning it the new value. If the object is immutable, then the assignment creates new object and the other one is untouched. However, it is not caused by how the object was passed into the procedure. It is the feature related to mutable/immutable in general. – pepr Sep 07 '20 at 19:32
  • @pepr - okay, thanks, I think I understand. I suppose the difference in behaviour between assigning the variable inside or outside a function is that inside a function, the 'labels' for the variables have a restricted scope. – Myridium Sep 18 '20 at 11:43
  • @Myridium: Well, not exactly. After passing the argument, both outer and inner variable point to the same target object. – pepr Sep 20 '20 at 00:05
  • apologies for the question, especially since the discussion seems to complain about using new terminology, but it's unclear to me. What does `pass by reference values` mean? Perhaps defining it in your answer would be useful :) Is a reference a pointer like thing? – Charlie Parker May 04 '21 at 20:03
  • @CharlieParker: I the third paragraph: "You can think about a reference value as the address of the target object." Anyway, this holds only for C-Python. Technically the function `id()` can return a different kind of unique identifier -- then that would be the reference value. Yes, I consider reference as equal to pointer that is never `null`. But pointers in compiled languages store the address. In Python, the reference/pointer is hidden and can possibly generalized for other kind of id's. – pepr May 05 '21 at 21:49
  • "The problem is that Python variable has not the same terminology meaning as in other languages." We have perfectly standard terminology for it: Python variables (or, if you prefer, "names" - as Python documentation calls them) have *reference semantics*. And those variables are *passed* by value (some newer sources use the term "pass by assignment", but this **means the same thing**, it's just thought to be clearer in the presence of variables with reference semantics). We know this because *plain assignment* inside the function *cannot affect* the caller's variable. – Karl Knechtel Jul 12 '23 at 16:40
  • @KarlKnechtel: As I wrote above, that is only playing on words. Python *reference semantics* differs from the C++ *reference semantics*. What is the *plain assignment* in your comment? – pepr Jul 14 '23 at 10:22
  • No, they do not. "reference semantics" is a property **of variables, not of parameters or parameter passing**. Python's names *have* reference semantics: they are hidden behind a layer of indirection. C++'s variables do not: they are not. But there is only one kind of "reference semantics". C++ references are not objects (in the general CS sense, not the OOP sense), so they cannot have either reference or value semantics. By "plain assignment", I mean the use of the `=` operator (distinguished from augmented assignment such as `+=`). – Karl Knechtel Jul 14 '23 at 14:59
  • @KarlKnechtel: Ok. When you speak about the *value of a variable* with someone else (who possibly do not knows internals of Python)... What is the value of a variable? The "plain assignment" *can* affect the caller's variable, because you can pass the object that defines its own operator `=` . – pepr Jul 15 '23 at 22:10
  • "because you can pass the object that defines its own operator `=`" - not in Python, you can't. That's *fundamentally* not possible (and therefore, not designed for) because assignment *binds names to objects* - it does not mutate objects to have the state of other objects. "When you speak about the value of a variable" - well, I *didn't*; but clearly in Python it means the indirected contents that represent the state of the object, and does not mean the layer of indirection itself. In C++, it still means the memory representing the state of the object - there just isn't that indirection. – Karl Knechtel Jul 15 '23 at 22:15
  • If you're still skeptical, please try to write the Python equivalent of `void swap(T& x, T& y) { T z = x; x = y; y = z; }`. You will find that no matter what you try, it does not actually swap anything for the caller, unless you wrap `x` and `y` in some other mutable object and mutate that. – Karl Knechtel Jul 15 '23 at 22:21
  • @KarlKnechtel: OK. I was wrong about the `operator=`. Anyway, *passing by value* is kind of equivalent with "no possibility to modify the original object". And that includes also passing objects. Do you agree? And a *variable*--typically in compiled languages--are considered *a space to store a value* rather than a *name*. – pepr Jul 17 '23 at 06:57
  • "Anyway, passing by value is kind of equivalent with "no possibility to modify the original object". " No; it's equivalent with "no possibility to modify the *caller's variable*. Passing a pointer in C isn't "pass-by-reference" either. "And a variable--typically in compiled languages--are considered a space to store a value rather than a name." Python chose the terminology "name" to avoid old baggage, but the only reason people see the term "variable" this way" is because of all the older languages that used value semantics for variables. – Karl Knechtel Jul 17 '23 at 17:22
60

A simple trick I normally use is to just wrap it in a list:

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

variable = ['Original']
self.Change(variable)      
print variable[0]

(Yeah I know this can be inconvenient, but sometimes it is simple enough to do this.)

AmanicA
  • 4,659
  • 1
  • 34
  • 49
28

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' )
Alex L
  • 8,748
  • 5
  • 49
  • 75
bobobobo
  • 64,917
  • 62
  • 258
  • 363
22

Python’s pass-by-assignment scheme isn’t quite the same as C++’s reference parameters option, but it turns out to be very similar to the argument-passing model of the C language (and others) in practice:

  • Immutable arguments are effectively passed “by value.” Objects such as integers and strings are passed by object reference instead of by copying, but because you can’t change immutable objects in place anyhow, the effect is much like making a copy.
  • Mutable arguments are effectively passed “by pointer.” Objects such as lists and dictionaries are also passed by object reference, which is similar to the way C passes arrays as pointers—mutable objects can be changed in place in the function, much like C arrays.
ajknzhol
  • 6,322
  • 13
  • 45
  • 72
22

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.

Mike Mazur
  • 2,509
  • 1
  • 16
  • 26
19

There are a lot of insights in answers here, but I think an additional point is not clearly mentioned here explicitly. Quoting from Python documentation What are the rules for local and global variables in Python?

In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a new value anywhere within the function’s body, it’s assumed to be a local. If a variable is ever assigned a new value inside the function, the variable is implicitly local, and you need to explicitly declare it as ‘global’. Though a bit surprising at first, a moment’s consideration explains this. On one hand, requiring global for assigned variables provides a bar against unintended side-effects. On the other hand, if global was required for all global references, you’d be using global all the time. You’d have to declare as global every reference to a built-in function or to a component of an imported module. This clutter would defeat the usefulness of the global declaration for identifying side-effects.

Even when passing a mutable object to a function this still applies. And to me it clearly explains the reason for the difference in behavior between assigning to the object and operating on the object in the function.

def test(l):
    print "Received", l, id(l)
    l = [0, 0, 0]
    print "Changed to", l, id(l)  # New local object created, breaking link to global l

l = [1, 2, 3]
print "Original", l, id(l)
test(l)
print "After", l, id(l)

gives:

Original [1, 2, 3] 4454645632
Received [1, 2, 3] 4454645632
Changed to [0, 0, 0] 4474591928
After [1, 2, 3] 4454645632

The assignment to an global variable that is not declared global therefore creates a new local object and breaks the link to the original object.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Joop
  • 7,840
  • 9
  • 43
  • 58
18

As you can state you need to have a mutable object, but let me suggest you to check over the global variables as they can help you or even solve this kind of issue!

http://docs.python.org/3/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python

example:

>>> def x(y):
...     global z
...     z = y
...

>>> x
<function x at 0x00000000020E1730>
>>> y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
>>> z
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'z' is not defined

>>> x(2)
>>> x
<function x at 0x00000000020E1730>
>>> y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
>>> z
2
John Smith
  • 7,243
  • 6
  • 49
  • 61
Nuno Aniceto
  • 1,892
  • 1
  • 15
  • 16
  • 5
    I was tempted to post a similar response- the original questioner may not have known that what he wanted was in fact to use a global variable, shared among functions. Here's the link I would have shared: http://stackoverflow.com/questions/423379/using-global-variables-in-a-function-other-than-the-one-that-created-them In answer to @Tim, Stack Overflow is not only a question and answer site, it's a vast repository of reference knowledge that only gets stronger and more nuanced- much like an active wiki- with more input. – Max P Magee Jun 30 '14 at 18:39
10

Here is the simple (I hope) explanation of the concept pass by object used in Python.
Whenever you pass an object to the function, the object itself is passed (object in Python is actually what you'd call a value in other programming languages) not the reference to this object. In other words, when you call:

def change_me(list):
   list = [1, 2, 3]

my_list = [0, 1]
change_me(my_list)

The actual object - [0, 1] (which would be called a value in other programming languages) is being passed. So in fact the function change_me will try to do something like:

[0, 1] = [1, 2, 3]

which obviously will not change the object passed to the function. If the function looked like this:

def change_me(list):
   list.append(2)

Then the call would result in:

[0, 1].append(2)

which obviously will change the object. This answer explains it well.

Community
  • 1
  • 1
matino
  • 17,199
  • 8
  • 49
  • 58
  • 3
    The problem is that the assignment does something else than you expect. The `list = [1, 2, 3]` causes reusing the `list` name for something else and forgeting the originally passed object. However, you can try `list[:] = [1, 2, 3]` (by the way `list` is wrong name for a variable. Thinking about `[0, 1] = [1, 2, 3]` is a complete nonsense. Anyway, what do you think means *the object itself is passed*? What is copied to the function in your opinion? – pepr Oct 03 '12 at 20:46
  • @pepr objects aren't literals. They are objects. The only way to talk about them is giving them some names. That's why it's so simple once you grasp it, but enormously complicated to explain. :-) – Veky May 09 '14 at 09:10
  • @Veky: I am aware of that. Anyway, the list literal is converted to the list object. Actually, any object in Python can exist without a name, and it can be used even when not given any name. And you can think about them as about anonymous objects. Think about objects being the elements of a lists. They need not a name. You can access them through indexing of or iterating through the list. Anyway, I insist on `[0, 1] = [1, 2, 3]` is simply a bad example. There is nothing like that in Python. – pepr May 12 '14 at 11:05
  • @pepr: I don't necessarily mean Python-definition names, just ordinary names. Of course `alist[2]` counts as a name of a third element of alist. But I think I misunderstood what your problem was. :-) – Veky May 12 '14 at 12:35
  • Argh. My English is obviously much worse than my Python. :-) I'll try just once more. I just said you have to give object some names just to talk about them. By that "names" I didn't mean "names as defined by Python". I know Python mechanisms, don't worry. – Veky May 15 '14 at 05:20
10

Aside from all the great explanations on how this stuff works in Python, I don't see a simple suggestion for the problem. As you seem to do create objects and instances, the Pythonic way of handling instance variables and changing them is the following:

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

    def Change(self):
        self.variable = 'Changed'

In instance methods, you normally refer to self to access instance attributes. It is normal to set instance attributes in __init__ and read or change them in instance methods. That is also why you pass self as the first argument to def Change.

Another solution would be to create a static method like this:

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

    @staticmethod
    def Change(var):
        var = 'Changed'
        return var
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dolf Andringa
  • 2,010
  • 1
  • 22
  • 36
9

I used the following method to quickly convert some Fortran code to Python. True, it's not pass by reference as the original question was posed, but it is a simple workaround in some cases.

a = 0
b = 0
c = 0

def myfunc(a, b, c):
    a = 1
    b = 2
    c = 3
    return a, b, c

a, b, c = myfunc(a, b, c)
print a, b, c
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Brad Porter
  • 449
  • 4
  • 6
  • Yes, this solves the 'pass by reference' in my use case as well. I have a function that basically cleans up values in a `dict` and then returns the `dict`. However, while cleaning up it may become apparent a rebuild of a part of the system is required. Therefore, the function must not only return the cleaned `dict` but also be able to signal the rebuild. I tried to pass a `bool` by reference, but ofc that doesn't work. Figuring out how to solve this, I found your solution (basically returning a tuple) to work best while also not being a hack/workaround at all (IMHO). – kasimir May 01 '20 at 16:08
8

To simulate passing an object by reference, wrap it in a one-item list:

class PassByReference:
    def __init__(self, name):
        self.name = name

def changeRef(ref):
    ref[0] = PassByReference('Michael')

obj = PassByReference('Peter')
print(obj.name)

p = [obj]
changeRef(p)

print(p[0].name)

Assigning to an element of the list mutates the list rather than reassigning a name. Since the list itself has reference semantics, the change is reflected in the caller.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
itmuckel
  • 1,300
  • 15
  • 23
  • `p` is reference to a mutable list object which in turn stores the object `obj`. The reference 'p', gets passed into `changeRef`. Inside `changeRef`, a new reference is created (the new reference is called `ref`) that points to the same list object that `p` points to. But because lists are mutable, changes to the list are visible by *both* references. In this case, you used the `ref` reference to change the object at index 0 so that it subsequently stores the `PassByReference('Michael')` object. The change to the list object was done using `ref` but this change is visible to `p`. – Minh Tran Oct 20 '18 at 03:19
  • So now, the references `p` and `ref` point to a list object that stores the single object, `PassByReference('Michael')`. So it follows that `p[0].name` returns `Michael`. Of course, `ref` has now gone out of scope and may be garbage collected but all the same. – Minh Tran Oct 20 '18 at 03:22
  • 1
    You have *not* changed the private instance variable, `name`, of the original `PassByReference` object associated with the reference `obj`, though. In fact, `obj.name` will return `Peter`. The aforementioned comments assumes the definition `Mark Ransom` gave. – Minh Tran Oct 20 '18 at 03:25
  • 1
    Point being, I don't agree that it's a *hack* (which I take to mean to refer to something that works but for reasons unknown, untested, or unintended by the implementer). You simply replaced one `PassByReference` object with another `PassByReference` object in your list and referred to the latter of the two objects. – Minh Tran Oct 20 '18 at 03:32
6

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.

Daniel Jour
  • 15,896
  • 2
  • 36
  • 63
4

Given the way Python handles values and references to them, the only way you can reference an arbitrary instance attribute is by name:

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

    def change(self, var):
        self.__dict__[var] = 'Changed'

In real code you would, of course, add error checking on the dict lookup.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mARK bLOORE
  • 166
  • 2
  • 7
4

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
Liakos
  • 512
  • 5
  • 10
3

While pass by reference is nothing that fits well into Python and should be rarely used, there are some workarounds that actually can work to get the object currently assigned to a local variable or even reassign a local variable from inside of a called function.

The basic idea is to have a function that can do that access and can be passed as object into other functions or stored in a class.

One way is to use global (for global variables) or nonlocal (for local variables in a function) in a wrapper function.

def change(wrapper):
    wrapper(7)

x = 5

def setter(val):
    global x
    x = val

print(x)

The same idea works for reading and deleting a variable.

For just reading, there is even a shorter way of just using lambda: x which returns a callable that when called returns the current value of x. This is somewhat like "call by name" used in languages in the distant past.

Passing 3 wrappers to access a variable is a bit unwieldy so those can be wrapped into a class that has a proxy attribute:

class ByRef:
    def __init__(self, r, w, d):
        self._read = r
        self._write = w
        self._delete = d
    def set(self, val):
        self._write(val)
    def get(self):
        return self._read()
    def remove(self):
        self._delete()
    wrapped = property(get, set, remove)

# Left as an exercise for the reader: define set, get, remove as local functions using global / nonlocal
r = ByRef(get, set, remove)
r.wrapped = 15

Pythons "reflection" support makes it possible to get a object that is capable of reassigning a name/variable in a given scope without defining functions explicitly in that scope:

class ByRef:
    def __init__(self, locs, name):
        self._locs = locs
        self._name = name
    def set(self, val):
        self._locs[self._name] = val
    def get(self):
        return self._locs[self._name]
    def remove(self):
        del self._locs[self._name]
    wrapped = property(get, set, remove)

def change(x):
    x.wrapped = 7

def test_me():
    x = 6
    print(x)
    change(ByRef(locals(), "x"))
    print(x)

Here the ByRef class wraps a dictionary access. So attribute access to wrapped is translated to a item access in the passed dictionary. By passing the result of the builtin locals and the name of a local variable, this ends up accessing a local variable. The Python documentation as of 3.5 advises that changing the dictionary might not work, but it seems to work for me.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
textshell
  • 1,746
  • 14
  • 21
  • Re *"The Python documentation as of 3.5"*: Can you add the reference? (But **** ***without*** **** "Edit:", "Update:", or similar - the answer should appear as if it was written today.) – Peter Mortensen Feb 18 '23 at 20:29
3

Since your example happens to be object-oriented, you could make the following change to achieve a similar result:

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

    def change(self, var):
        setattr(self, var, 'Changed')

# o.variable will equal 'Changed'
o = PassByReference()
assert o.variable == 'Changed'
Jesse Hogan
  • 3,075
  • 2
  • 16
  • 17
3

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)
sergzach
  • 6,578
  • 7
  • 46
  • 84
2

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

  • Java and C#: primitive types (including string) pass by value (copy). A 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). 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. For example, 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 reassigning/re-initializing the mutable variable is that updated value gets reflected back in the called function whereas the reinitialized value does not. The 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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Alok Garg
  • 164
  • 9
  • 2
    Old but I feel obliged to correct it. Strings are passed by reference in both Java and C#, NOT by value – John Sep 11 '19 at 16:39
  • 1
    No. Everything is passed by value in c#. It is that the value of variable that is an object in c# is exactly and heap ID/address of the object. So when you set something in a function to a new object you set the variable in function to address. Passing by reference means passing an adres to value which is an address to the value for struct types but address to pointer in case of objects. – jjaskulowski Nov 10 '21 at 21:13
1

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. There isn't any 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
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Magnus
  • 1,584
  • 19
  • 14
  • 4
    "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" No, you can't. What you are doing is returning a single value, a `tuple`, which is what the expression `a, b, c` creates. You then use *iterable unpacking* to unpack that tuple into separate variables. Of course, in effect, you can think of this as "returning multiple values", but you aren't actually doing that, you are returning a container. – juanpa.arrivillaga Aug 12 '20 at 19:45
  • 2
    @juanpa.arrivillaga, yes, I was aware of that when I wrote my answer, I had just read about it. But I just described the whole thing in a practical way without going into the details of how it works and add unnecessary length to my answer. You can indeed return multiple values from a function, if it is done in an object or similar, like in a tuple (which in Python is taken care of in the neat way I showed). When I order things from a company, they can send me multiple things, even if it is all in one package. – Magnus Aug 13 '20 at 09:01
  • This rambles a lot and is mostly off the topic of OP's question. It refers instead to this concept: https://stackoverflow.com/questions/354883 - which is well addressed by other existing Q&A. – Karl Knechtel Jul 12 '23 at 17:22
1

Alternatively, you could use ctypes which 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 apparently passed by reference. However, you have to be careful as strange things could happen, and it is therefore not advised.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Julian wandhoven
  • 268
  • 2
  • 11
1

Use dataclasses. Also, it allows you to apply type restrictions (aka "type hints").

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 an explicit context class though. When prototyping, I prefer dataclasses, just because it's easy to serialize them back and forth.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 1.9 mill views and 13 years later a decent solution comes up. I have implemented it calling the Holder "State" and adding a boolean value that can now be modified in a different function ... excellent and clean! – Wolfgang Fahl Nov 27 '22 at 17:12
  • @WolfgangFahl several prior answers do functionally the same thing, just with a list element, ordinary object attribute etc. instead of a dataclass instance attribute. They all fundamentally work in the same way: since passing an object with reference semantics by value allows for mutation but not reassignment, we convert the desired reassignment into mutation by creating a wrapper object. – Karl Knechtel Jul 12 '23 at 17:11
  • Agreed with @Karl Knechtel totally. Only reason I highlighted this case is that dataclasses support are quite friendly for serialization and provide minimum confusing API. So if somebody will extend your code there will be no temptation to perform list operations on what you supposed to use as a ref holder. – Stepan Dyatkovskiy Jul 16 '23 at 08:35
1

There are already many great answers (or let's say opinions) about this and I've read them, but I want to mention a missing one. The one from Python's documentation in the FAQ section. I don't know the date of publishing this page, but this should be our true reference:

Remember that arguments are passed by assignment in Python. Since assignment just creates references to objects, there’s no alias between an argument name in the caller and callee, and so no call-by-reference per se.

If you have:

a = SOMETHING

def fn(arg):
    pass

and you call it like fn(a), you're doing exactly what you do in assignment. So this happens:

arg = a

An additional reference to SOMETHING is created. Variables are just symbols/names/references. They don't "hold" anything.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
S.B
  • 13,077
  • 10
  • 22
  • 49
0

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)
Jop Knoppers
  • 676
  • 1
  • 10
  • 22
0
  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)
Youjun Hu
  • 991
  • 6
  • 18
0

My Tests:

#objects:
def change_me(dict):
    dict.update(b=10, c=10)

d = {'a': 1, 'b': 1}
change_me(d)
d
{'a': 1, 'b': 10, 'c': 10}
# conclusion: objects are passed by reference
#strings:
def change_me(str):
    str = 'another string'

d = 'a string'
change_me(d)
d
'a string'
# conclusion: strings are passed by value
# you may return a value and capture it again
# like:  d = change_me(d)
Fernando Fabreti
  • 4,277
  • 3
  • 32
  • 33
0

I found other answers a little bit confusing and I had to struggle a while to grasp the concepts. So, I am trying to put the answer in my language. It may help you if other answers are confusing to you too. So, the answer is like this-

When you create a list-

my_list = []

you are actually creating an object of the class list:

my_list = list()

Here, my_list is just a name given to the memory address (e.g., 140707924412080) of the object created by the constructor of the 'list' class.

When you pass this list to a method defined as

def my_method1(local_list):
    local_list.append(1)

another reference to the same memory address 140707924412080 is created. So, when you make any changes/mutate to the object by using append method, it is also reflected outside the my_method1. Because, both the outer list my_list and local_list are referencing the same memory address.

On the other hand, when you pass the same list to the following method,

def my_method2(local_list2):
    local_list2 = [1,2,3,4]

the first half of the process remains the same. i.e., a new reference/name local_list2 is created which points to the same memory address 140707924412080. But when you create a new list [1,2,3,4], the constructor of the 'list' class is called again and a new object is created. This new object has a completely different memory address, e.g., 140707924412112. When you assign local_list2 to [1,2,3,4], now the local_list2 name refers to a new memory address which is 140707924412112. Since in this entire process you have not made any changes to the object placed at memory address 140707924412080, it remains unaffected.

In other words, it is in the spirit that 'other languages have variables, Python have names'. That means in other languages, variables are referenced to a fixed address in memory. That means, in C++, if you reassign a variable by

a = 1
a = 2

the memory address where the value '1' was stored is now holding the value '2' And hence, the value '1' is completely lost. Whereas in Python, since everything is an object, earlier 'a' referred to the memory address that stores the object of class 'int' which in turn stores the value '1'. But, after reassignment, it refers to a completely different memory address that stores the newly created object of class 'int' holding the value '2'.

Hope it helps.

Bhanuday Sharma
  • 323
  • 3
  • 10
0

A method's argument is "passed by assignment": a reference to an object is passed by value.

With

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

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

passbyref = PassByReference()

we can witness that rebinding a value to the reference copy passed as an argument will will not change the value bound to the object in the outer scope.

A way to circumvent is to pass your (mutable) argument as a one-element list, and alter its first (and unique) value in the body of the method.

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

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

passbyref = PassByReference()
kiriloff
  • 25,609
  • 37
  • 148
  • 229
-1

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")
TVK
  • 1,042
  • 7
  • 21
-2

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'
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
JustBeingHelpful
  • 18,332
  • 38
  • 160
  • 245
-2

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
eyal0931
  • 59
  • 6
-2
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 . . . ")
vvvvv
  • 25,404
  • 19
  • 49
  • 81
Celes
  • 27
  • 1
  • 5
-2

I share another fun way for people to comprehend this topic over a handy tool - Python Tutor: Learn Python, JavaScript, C, C++, and Java programming by visualizing code 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

  2. Passing a List

    Enter image description here

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
paulyang0125
  • 307
  • 2
  • 7
  • It would be much clearer that this is not a tool recommendation if the images contained free-hand circles to ***highlight*** the essential part for this answer. The images also ought to be cropped and otherwise reduced in size to the absolute minimum. – Peter Mortensen Feb 18 '23 at 21:15
-3

A 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 (i.e., 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, and 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, and c now have different values here
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mo FEAR
  • 552
  • 4
  • 8
  • 3
    "For basic types, python and c++ also behave the same to each other, in that copies of the instances are now made", no that is not correct. Copies of objects *are never made as part of the evaluation strategy* – juanpa.arrivillaga Dec 17 '21 at 05:01
  • Your comment makes no sense. Are you speaking of python or c++? If python, then how the interpreter goes about differs whether they are basic types or not. Internally python uses an equivalent of a stack to manage local basic object types, and these are copies. If they weren't, then the originals outside the function call would be irreversibly modified, which they arent, which raises the question, have you ever even used python?! – mo FEAR Dec 21 '21 at 22:54
  • 3
    I'm speaking of Python. The interpreter *makes no distinction between "basic types" and "other types"* And in CPython at least, **all objects are allocated on a privately managed heap**. You seem to have no basic knowledge about the internals of Python, let alone the semantics of the langauge – juanpa.arrivillaga Dec 21 '21 at 23:47
  • 1
    The objects aren't modified **by assignment to the parameter**, but **that works that way for all objects**, because it isn't an issue of the *type* of object, but rather, the semantics of assignment and the evaluation strategy. In Python, *some types are merely immutable*. that is, they *expose no mutator methods*. However, we *can* (if we are willing to delve into implementation details) mutate them, and indeed, you'll see the evaluation strategy is exactly the same – juanpa.arrivillaga Dec 21 '21 at 23:49
  • This isn't about objects! It's about BASIC TYPES. Python treats them behind the scenes as objects, and they have to exist somewhere in memory. But when passed as parameters to a function, COPIES have to be made (by fundamental rules of information theory), otherwise when the function returns, the original variables that were passed to the function, would also get modified. BUT THEY DON'T. TRY IT (Excuse the caps, I don't know how to achieve the bold effect). They only way this can be the case, is if there is a COPY somewhere else in memory, which is point of what is above. – mo FEAR Jan 03 '22 at 15:10
  • In other words... one way or another, irrespective how you consider it from a philosophical standpoint, python DOES treat basic types DIFFERENTLY than it does for "other types", just like C++. Saying "by assignment to the parameter" is pointless and philosophical, since if you change a basic type that is a member of "another type", using THAT SAME ASSIGNMENT OPERATOR, then UNLIKE "other types", the actual value DOES change, irrespective from where it is referenced after that. – mo FEAR Jan 03 '22 at 15:13
  • To clarify (since the last statement above is not fully correct but I can't edit it anymore: If you assign to an "other type", you are changing what instance it points to, without necessarily deleting the original instance (as long as it is pointed to by another reference). When you do this to a basic type though, even though it's technically an object in python, python still changes its actual value in memory, rather than what instance (or address) that reference points to. Python doesn't create a new instance (or memory location) just because you changed the value of an int, and then garbage – mo FEAR Jan 03 '22 at 15:24
  • collect the old one, although it would do this for "other types". And this difference holds despite using the same assignment operator in all cases. – mo FEAR Jan 03 '22 at 15:25
  • 2
    you are simply mistaken. What you are calling "basic types" are not treated *in any way differently* when they are passed to functions or by the assignment operator. You are operating under totally false premises. – juanpa.arrivillaga Jan 03 '22 at 20:32
  • i.e. "If you assign to an "other type", you are changing what instance it points to, without necessarily deleting the original instance (as long as it is pointed to by another reference). When you do this to a basic type though, even though it's technically an object in python, python still changes its actual value in memory, rather than what instance (or address) that reference points to. " is *totally incorrect*, assuming what you are saying is even coherent (it isn't, one doesn't *assign to types*, you assign to *variables*). – juanpa.arrivillaga Jan 03 '22 at 20:33