108

In some languages you can pass a parameter by reference or value by using a special reserved word like ref or val. When you pass a parameter to a Python function it never alters the value of the parameter on leaving the function.The only way to do this is by using the global reserved word (or as i understand it currently).

Example 1:

k = 2

def foo (n):
     n = n * n     #clarity regarding comment below
     square = n
     return square

j = foo(k)
print j
print k

would show

>>4
>>2

showing k to be unchanged.

In this example the variable n is never changed

Example 2:

n = 0
def foo():
    global n
    n = n * n
    return n

In this example the variable n is changed.

Is there any way in Python to call a function and tell Python that the parameter is either a value or reference parameter instead of using global?

dreftymac
  • 31,404
  • 26
  • 119
  • 182
Timothy Lawman
  • 2,194
  • 6
  • 24
  • 33
  • 5
    The best resource I've found for understanding python's calling model is this article on effbot: http://effbot.org/zone/call-by-object.htm – Wilduck Nov 08 '12 at 23:04
  • 1
    you should read about Python variables, mutable and inmutable objects. Also in your first example why would `n` be changed, you are using a new variable `square` to store the result of your calculation. – Facundo Casco Nov 08 '12 at 23:07
  • 2
    Also, have a look at this previous StackOverflow answer. http://stackoverflow.com/a/10262945/173292 It explains the call by object reference model fairly intuitively. – Wilduck Nov 08 '12 at 23:41
  • 1
    See also this SO question for very useful explanation: [how do I pass a variable by reference](http://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference) – Michael Ohlrogge Sep 13 '16 at 14:22
  • I have a work around: to pass a to function() by reference: list=[a]; function(list[0]); now the data in list is a reference. I'm not posting as an answer because this seems like the wrong way but I'd love to be told the correct way to do this – Supamee Jul 19 '17 at 16:04

12 Answers12

219

There are essentially three kinds of 'function calls':

  • Pass by value
  • Pass by reference
  • Pass by object reference

Python is a PASS-BY-OBJECT-REFERENCE programming language.

Firstly, it is important to understand that a variable, and the value of the variable (the object) are two seperate things. The variable 'points to' the object. The variable is not the object. Again:

THE VARIABLE IS NOT THE OBJECT

Example: in the following line of code:

>>> x = []

[] is the empty list, x is a variable that points to the empty list, but x itself is not the empty list.

Consider the variable (x, in the above case) as a box, and 'the value' of the variable ([]) as the object inside the box.

PASS BY OBJECT REFERENCE (Case in python):

Here, "Object references are passed by value."

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x

Here, the statement x = [0] makes a variable x (box) that points towards the object [0].

On the function being called, a new box li is created. The contents of li are the SAME as the contents of the box x. Both the boxes contain the same object. That is, both the variables point to the same object in memory. Hence, any change to the object pointed at by li will also be reflected by the object pointed at by x.

In conclusion, the output of the above program will be:

[0, 1]

Note:

If the variable li is reassigned in the function, then li will point to a separate object in memory. x however, will continue pointing to the same object in memory it was pointing to earlier.

Example:

def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x

The output of the program will be:

[0]

PASS BY REFERENCE:

The box from the calling function is passed on to the called function. Implicitly, the contents of the box (the value of the variable) is passed on to the called function. Hence, any change to the contents of the box in the called function will be reflected in the calling function.

PASS BY VALUE:

A new box is created in the called function, and copies of contents of the box from the calling function is stored into the new boxes.

starball
  • 20,030
  • 7
  • 43
  • 238
Shobhit Verma
  • 2,223
  • 2
  • 10
  • 17
  • 4
    Could you give examples of "pass by reference" and "pass by value" like you did for "pass by object reference". – TJain Oct 26 '17 at 00:41
  • @TJain Pass by reference and pass by value can be seen in C++. This answer gives a good explanation: https://stackoverflow.com/a/430958/5076583 – Shobhit Verma Oct 27 '17 at 02:51
  • 6
    I still don't understand how this differs from pass-by-reference. This answer desperately needs an example of how identical pseudocode would produce different outputs for all 3 paradigms. Linking to a different answer which only explains the difference between pass-by-reference and pass-by-value doesn't help. – Jess Riedel Jan 22 '18 at 00:02
  • Is it not more simple to say that "all variables in Python are **pointers**" and "all variables assigned to parameters in a function call are assigned to new pointers?". If you realize this, you'll see that Python is like Java: it simply always **pass pointers by value**. See [Kirk Strauser's answer](https://stackoverflow.com/a/13300388/1763602) – Marco Sulla Jan 01 '20 at 10:55
  • @MarcoSulla no. Because *Python doesn't have pointers*. This is a silly Javaism, necessitated by the fact that Java has "primitive types" and "reference types". Such a distinction doesn't exist. – juanpa.arrivillaga Nov 03 '21 at 16:48
  • @JessRiedel simple, if you had call by reference, you could have a function, `def foo(&x): x = 42`, I am borrowing syntax from C++ pass by reference paramters, no such & syntax exists in Python. Anyway, suppose, in some other, arbitrary scope, you have `i = 0; foo(i); print(i)` would print `42`. This is not possible in Python, because Python *does not support call by reference*\ – juanpa.arrivillaga Nov 03 '21 at 16:49
  • @juanpa.arrivillaga Also Java does not have pointers. But most famous implementation of Python, CPython, is written in C, and of course it uses pointers. Any Python object is only a pointer of type `PyObject*` – Marco Sulla Nov 03 '21 at 19:37
  • @MarcoSulla no, it isn't. Python objects are python objects, they aren't pointers. **Python doesn't have pointers**. Look, if I implemented Python entirely in Fortran, that wouldn't mean that Python suddenly becomes call by reference. This is confusing the *implementation* for the semantics. – juanpa.arrivillaga Nov 03 '21 at 19:40
  • Furthermore, you can use the builtin module `ctypes`, that uses explicitly pointers – Marco Sulla Nov 03 '21 at 19:40
  • @juanpa.arrivillaga ok, Python objects are not pointers, but the move as pointers and quack as pointers.... – Marco Sulla Nov 03 '21 at 19:42
  • @MarcoSulla no, they don't. Can I dereference these pointers? Can I use pointer arithmetic with these pointers? No because they aren't pointers. – juanpa.arrivillaga Nov 03 '21 at 19:46
  • @juanpa.arrivillaga you are right, but when comes to explain to a person if Python is pass by value or pass by reference, it's quite obvious and simple to explain the internals of CPython and the `PyObject*`. This way is quite obvious that if you have a list `a` and you do `b = a`, you're not creating a new list, but you're referencing the same list with a different alias. Furthermore, the Python C API is well documented and so the `PyObject`: https://docs.python.org/3/c-api/structures.html#c.PyObject – Marco Sulla Nov 03 '21 at 20:31
  • I would add that also PyPy, the more abstract implementation of Python, internally uses pointers. They are not exposed to the user, but it's important to know that they exists in the background to understand fully how a language works. – Marco Sulla Nov 03 '21 at 20:42
88

You can not change an immutable object, like str or tuple, inside a function in Python, but you can do things like:

def foo(y):
  y[0] = y[0]**2

x = [5]
foo(x)
print x[0]  # prints 25

That is a weird way to go about it, however, unless you need to always square certain elements in an array.

Note that in Python, you can also return more than one value, making some of the use cases for pass by reference less important:

def foo(x, y):
   return x**2, y**2

a = 2
b = 3
a, b = foo(a, b)  # a == 4; b == 9

When you return values like that, they are being returned as a Tuple which is in turn unpacked.

edit: Another way to think about this is that, while you can't explicitly pass variables by reference in Python, you can modify the properties of objects that were passed in. In my example (and others) you can modify members of the list that was passed in. You would not, however, be able to reassign the passed in variable entirely. For instance, see the following two pieces of code look like they might do something similar, but end up with different results:

def clear_a(x):
  x = []

def clear_b(x):
  while x: x.pop()

z = [1,2,3]
clear_a(z) # z will not be changed
clear_b(z) # z will be emptied
Starman
  • 336
  • 2
  • 11
dave mankoff
  • 17,379
  • 7
  • 50
  • 64
  • 2
    It would be helpful to see the results of the programs. For example does 'print x[0]' return 25? (Yes it does, but that should be shown.) – Ray Salemi Sep 03 '17 at 17:13
  • 12
    @alexey `clear_a` is given a reference to `z` and stores that reference in `x`. It then immediately changes `x` to reference a different array. The original `z` array is forgotten about in the scope of `clear_a`, but is not actually changed. It continues unchanged when returning to the global scope. Contrast that with `clear_b` which takes a reference to `z` and then operates directly on it, without ever creating a new array or otherwise pointing `x` and something different. – dave mankoff Sep 08 '17 at 14:21
  • thanks dave! I tried "creating a new array" in clear_b, `y = x`, `y: y.pop()` and then called `clear_b(z)`, z still got emptied... So we need something like `y = list(x)` to create a copy of x (list(x) explained [here](http://henry.precheur.org/python/copy_list.html)) – alexey Sep 11 '17 at 18:59
  • ```run_thread = [True] t= threading.Thread(target=module2.some_method, \ args=(11,1,run_thread)) --do something - and when you want to sop run_thread[0] =False``` – Alex Punnen Feb 24 '19 at 11:08
  • There's no primitive type in Python, unlike Java. All types instance objects. – Marco Sulla Jan 01 '20 at 10:36
  • 1
    `Note that in Python, you can also return more than one value, making some of the use cases for pass by reference less important:..` Well not quite, as sometimes passing by reference has to do with memory management, not just with changing arguments values. Sometimes you don't want your arguments to be copied inside the routine. Specially if you are running short of memory. –  Feb 17 '20 at 11:35
  • C# has it simply equate to [def fn(ref x)] and called as fn(ref x), very easy to read. too bad it would not be supported as such in python. – Joseph Poirier Sep 08 '21 at 14:33
30

OK, I'll take a stab at this. Python passes by object reference, which is different from what you'd normally think of as "by reference" or "by value". Take this example:

def foo(x):
    print x

bar = 'some value'
foo(bar)

So you're creating a string object with value 'some value' and "binding" it to a variable named bar. In C, that would be similar to bar being a pointer to 'some value'.

When you call foo(bar), you're not passing in bar itself. You're passing in bar's value: a pointer to 'some value'. At that point, there are two "pointers" to the same string object.

Now compare that to:

def foo(x):
    x = 'another value'
    print x

bar = 'some value'
foo(bar)

Here's where the difference lies. In the line:

x = 'another value'

you're not actually altering the contents of x. In fact, that's not even possible. Instead, you're creating a new string object with value 'another value'. That assignment operator? It isn't saying "overwrite the thing x is pointing at with the new value". It's saying "update x to point at the new object instead". After that line, there are two string objects: 'some value' (with bar pointing at it) and 'another value' (with x pointing at it).

This isn't clumsy. When you understand how it works, it's a beautifully elegant, efficient system.

Kirk Strauser
  • 30,189
  • 5
  • 49
  • 65
  • 3
    But what if I *want* the function to alter the contents of my variable? I take it that there is no way to do this? – aquirdturtle May 21 '16 at 17:09
  • 1
    You can alter the object that the _name_ is pointing at, e.g. by appending to a list, if that object is mutable. There are no Python semantics for saying "alter the namespace of the scope that called me so that the name in my argument list now points at something different than when it called me". – Kirk Strauser May 21 '16 at 18:19
  • 2
    Effectively what I'm asking is if there's a simple way to get python not create a new pointer to the same object but to use the original pointer instead. I take it that there is no way to do this. I take it from other answers that the normal work-around to achieving what passing by reference does is just to return more parameters. if that's the case, I see some validity in the argument that a,b,c,d,e = foo(a,b,c,d,e) is a bit more clunky than just foo(a,b,c,d,e). – aquirdturtle May 21 '16 at 19:13
  • 2
    @aquirdturtle This is nothing to do by the fact that a new pointer is created. You have to return a new object because `str`ings, `tuple`s and other objects are **immutable**. If you pass a mutable object, like a `list`, you can change it inside the function, without the need to return it, because all function parameters are pointers to the same objects you passed. – Marco Sulla Jan 01 '20 at 11:06
  • @aquirdturtle Python doesn't create a "new pointer"... **python doesn't have pointers!** – juanpa.arrivillaga Nov 03 '21 at 16:50
  • @juanpa.arrivillaga In Python, all variables are effectively pointers. – Kirk Strauser Nov 03 '21 at 17:05
  • @KirkStrauser Python *doesn't have pointers*. How does one *dereference* a pointer in Python? Or use pointer arithmetic? You can't, because *python doesn't have pointers*. If you are trying to explain Python's semantics, talking about pointers is the wrong level of abstraction. The fact that CPython uses PyObject pointers is an *implementation detail* EDIT: Yes, to someone coming from a C-background, it may be helpful to say "references to Python objects act like pointers that are automatically dereferenced when you use them". Maybe. IMO it is almost always never a useful idea to bring up – juanpa.arrivillaga Nov 03 '21 at 17:18
  • @juanpa.arrivillaga Since this is the common analogy used to explain Python variables, please explain why you feel it's inaccurate. Where do you believe the metaphor breaks down? – Kirk Strauser Nov 03 '21 at 17:24
  • @KirkStrauser I am not saying it breaks down. It is a bad analogy that adds to a lot of confusion, especially to beginners or to people who have no experience with low-level languages (very common these days). It can be *accurate*, indeed, you could explain the semantics using an analogy to C entirely (hell, you could just show them the CPython source code). Python's semantics are very simple, and best explained on their own terms. No need to involve the idea of pointers. There are names in namespaces, that refer to objects. That's the right level of abstraction. – juanpa.arrivillaga Nov 03 '21 at 17:27
  • @KirkStrauser I think the *best* explanation of Python's semantics is Ned Batchelder's. [Facts and Myths about Python Names and Values](https://nedbatchelder.com/text/names.html). Note, it mentions pointers in passing, but the actual meat of it doesn't rely on the concept of pointers at all. – juanpa.arrivillaga Nov 03 '21 at 17:29
28

Hope the following description sums it up well:

There are two things to consider here - variables and objects.

  1. If you are passing a variable, then it's pass by value, which means the changes made to the variable within the function are local to that function and hence won't be reflected globally. This is more of a 'C' like behavior.

Example:

def changeval( myvar ):
   myvar = 20; 
   print "values inside the function: ", myvar
   return

myvar = 10;
changeval( myvar );
print "values outside the function: ", myvar

O/P:

values inside the function:  20 
values outside the function:  10
  1. If you are passing the variables packed inside a mutable object, like a list, then the changes made to the object are reflected globally as long as the object is not re-assigned.

Example:

def changelist( mylist ):
   mylist2=['a'];
   mylist.append(mylist2);
   print "values inside the function: ", mylist
   return

mylist = [1,2,3];
changelist( mylist );
print "values outside the function: ", mylist

O/P:

values inside the function:  [1, 2, 3, ['a']]
values outside the function:  [1, 2, 3, ['a']]
  1. Now consider the case where the object is re-assigned. In this case, the object refers to a new memory location which is local to the function in which this happens and hence not reflected globally.

Example:

def changelist( mylist ):
   mylist=['a'];
   print "values inside the function: ", mylist
   return

mylist = [1,2,3];
changelist( mylist );
print "values outside the function: ", mylist

O/P:

values inside the function:  ['a']
values outside the function:  [1, 2, 3]
Abhijeet Kasurde
  • 3,937
  • 1
  • 24
  • 33
attaboy182
  • 2,039
  • 3
  • 22
  • 28
  • 2
    This is the best summary! ^^^ BEST SUMMARY HERE ^^^ everyone read this answer! 1. pass simple variables 2. pass object reference which is modified 3. pass object reference which is reassigned in function – gaoithe Oct 25 '17 at 10:22
  • 5
    This answer is very confused. Python doesn't pass different kinds of values differently: all function arguments in Python receive their values by assignment, and behave exactly the same way assignment behaves anywhere else in the language. ("Although that way may not be obvious at first unless you're Dutch.") – Daniel Pryden Mar 15 '18 at 17:06
10

Python is neither pass-by-value nor pass-by-reference. It's more of "object references are passed by value" as described here:

  1. Here's why it's not pass-by-value. Because

    def append(list):
        list.append(1)
    
    list = [0]
    reassign(list)
    append(list)
    

returns [0,1] showing that some kind of reference was clearly passed as pass-by-value does not allow a function to alter the parent scope at all.

Looks like pass-by-reference then, hu? Nope.

  1. Here's why it's not pass-by-reference. Because

    def reassign(list):
      list = [0, 1]
    
    list = [0]
    reassign(list)
    print list
    

returns [0] showing that the original reference was destroyed when list was reassigned. pass-by-reference would have returned [0,1].

For more information look here:

If you want your function to not manipulate outside scope, you need to make a copy of the input parameters that creates a new object.

from copy import copy

def append(list):
  list2 = copy(list)
  list2.append(1)
  print list2

list = [0]
append(list)
print list
Zain Arshad
  • 1,885
  • 1
  • 11
  • 26
Philip Dodson
  • 337
  • 3
  • 9
10

Technically python do not pass arguments by value: all by reference. But ... since python has two types of objects: immutable and mutable, here is what happens:

  • Immutable arguments are effectively passed by value: string, integer, tuple are all immutable object types. While they are technically "passed by reference" (like all parameters), since you can't change them in-place inside the function it looks/behaves as if it is passed by value.

  • Mutable arguments are effectively passed by reference: lists or dictionaries are passed by its pointers. Any in-place change inside the function like (append or del) will affect the original object.

This is how Python is designed: no copies and all are passed by reference. You can explicitly pass a copy.

def sort(array):
    # do sort
    return array

data = [1, 2, 3]
sort(data[:]) # here you passed a copy

Last point I would like to mention which is a function has its own scope.

def do_any_stuff_to_these_objects(a, b): 
    a = a * 2 
    del b['last_name']

number = 1 # immutable
hashmap = {'first_name' : 'john', 'last_name': 'legend'} # mutable
do_any_stuff_to_these_objects(number, hashmap) 
print(number) # 1 , oh  it should be 2 ! no a is changed inisde the function scope
print(hashmap) # {'first_name': 'john'}
Watki02
  • 4,696
  • 7
  • 34
  • 36
Yasser Sinjab
  • 578
  • 6
  • 19
  • 1
    "Immutable arguments are effectively passed by value: string, integer, tuple are all passed by reference" this sentence has self-contradiction – eral Apr 17 '20 at 18:33
  • @eral, if you understand the full context, it does not contradict itself. I edited it to make this more clear. – Watki02 Sep 05 '20 at 15:31
3

So this is a little bit of a subtle point, because while Python only passes variables by value, every variable in Python is a reference. If you want to be able to change your values with a function call, what you need is a mutable object. For example:

l = [0]

def set_3(x):
    x[0] = 3

set_3(l)
print(l[0])

In the above code, the function modifies the contents of a List object (which is mutable), and so the output is 3 instead of 0.

I write this answer only to illustrate what 'by value' means in Python. The above code is bad style, and if you really want to mutate your values you should write a class and call methods within that class, as MPX suggests.

Isaac
  • 3,586
  • 1
  • 18
  • 20
  • this answers half the question so how would i write the same set_3(x) function so that it does not change the value of l but returns a new list that has been changed? – Timothy Lawman Nov 08 '12 at 23:31
  • Just make a new list and modify it: `y = [a for a in x]; y[0] = 3; return y` – Isaac Nov 08 '12 at 23:35
  • the whole thing involves lists and copying lists which goes in some ways to answer, but how can i do it with out having to convert an int to a list or is this the best we have? – Timothy Lawman Nov 08 '12 at 23:47
  • You can't modify a primitive argument like an int. You have to put it in some sort of container. My example put it in a list. You could also put it in a class or a dictionary. Really though, you should just reassign it outside a function with something like `x = foo(x)`. – Isaac Nov 08 '12 at 23:51
1

Consider that the variable is a box and the value it points to is the "thing" inside the box:

1. Pass by reference : function shares the same box and thereby the thing inside also.

2. Pass by value : function creates a new box, a replica of the old one, including a copy of whatever thing is inside it. Eg. Java - functions create a copy of the box and the thing inside it which can be: a primitive / a reference to an object. (note that the copied reference in the new box and the original both still point to the same object, here the reference IS the thing inside the box, not the object it is pointing to)

3. Pass by object-reference: the function creates a box, but it encloses the same thing the initial box was enclosing. So in Python:

a) if the thing inside said box is mutable, changes made will reflect back in the original box (eg. lists)

b) if the thing is immutable (like python strings and numeric types), then the box inside the function will hold the same thing UNTIL you try to change its value. Once changed, the thing in the function's box is a totally new thing compared to the original one. Hence id() for that box will now give the identity of the new thing it encloses.

0

The answer given is

def set_4(x):
   y = []
   for i in x:
       y.append(i)
   y[0] = 4
   return y

and

l = [0]

def set_3(x):
     x[0] = 3

set_3(l)
print(l[0])

which is the best answer so far as it does what it says in the question. However,it does seem a very clumsy way compared to VB or Pascal.Is it the best method we have?

Not only is it clumsy, it involves mutating the original parameter in some way manually eg by changing the original parameter to a list: or copying it to another list rather than just saying: "use this parameter as a value " or "use this one as a reference". Could the simple answer be there is no reserved word for this but these are great work arounds?

Timothy Lawman
  • 2,194
  • 6
  • 24
  • 33
0
class demoClass:
    x = 4
    y = 3
foo1 = demoClass()
foo1.x = 2
foo2 = demoClass()
foo2.y = 5
def mySquare(myObj):
    myObj.x = myObj.x**2
    myObj.y = myObj.y**2
print('foo1.x =', foo1.x)
print('foo1.y =', foo1.y)
print('foo2.x =', foo2.x)
print('foo2.y =', foo2.y)
mySquare(foo1)
mySquare(foo2)
print('After square:')
print('foo1.x =', foo1.x)
print('foo1.y =', foo1.y)
print('foo2.x =', foo2.x)
print('foo2.y =', foo2.y)
-2

In Python the passing by reference or by value has to do with what are the actual objects you are passing.So,if you are passing a list for example,then you actually make this pass by reference,since the list is a mutable object.Thus,you are passing a pointer to the function and you can modify the object (list) in the function body.

When you are passing a string,this passing is done by value,so a new string object is being created and when the function terminates it is destroyed. So it all has to do with mutable and immutable objects.

jkalivas
  • 1,117
  • 1
  • 8
  • 11
  • 1
    That's completely incorrect. Python always passes by "object reference" (which is different from variable reference). – Kirk Strauser Nov 09 '12 at 00:20
  • i meant the analogy mutable objects--pass by reference and immutable objects--pass by value.It is perfect valid what i am saying.You probably did not catch what i was saying – jkalivas Nov 09 '12 at 20:56
  • 1
    I caught it and it's wrong. It has nothing to do with whether an object is mutable or immutable; it's always done the same way. – Kirk Strauser Nov 09 '12 at 21:31
-2

Python already call by ref..

let's take example:

  def foo(var):
      print(hex(id(var)))


  x = 1 # any value
  print(hex(id(x))) # I think the id() give the ref... 
  foo(x)

OutPut

  0x50d43700 #with you might give another hex number deppend on your memory 
  0x50d43700
  • No, it's not true `def foo(var): print(id(var)) var = 1234 print(id(var)) x = 123 print(id(x)) # I think the id() give the ref... foo(x) print(id(x))` – Zohaib Ijaz Aug 23 '17 at 10:13