0

Code

def change1(list1):
        list1[1] = list1[1] + 5

def change2(number):
        number = number + 2

def main():
        numbers = [4, 8, 12]
        change1(numbers)
        variable = 15
        change2(variable)
        i = 0
        while i < 3:
                print numbers[i]
                i += 1
        print variable

main()

When I read it, I thought it will output 4 8 12 15 but it outputs 4 13 12 15. I can see here that Python deals with integer and lists differently, I assumed that the last thing is impossible without global. I cannot understand the output, in such case, why would it not output 4 13 12 17?

You can see here almost identical code with different types and different reference:

$ python test2.py 
4
13
12
15
$ python test3.py 
4
13
12
17
$ cat test2.py test3.py 

Pass-by-reference examples

test2.py: pass-by-reference and mutable data type -example. Table/list is not enough to affect the local variable in main, you need the Reference!

def change1(list1):
    list1[1] = list1[1] + 5

def change2(number):
    number = [x+2 for x in number]

def main():
    numbers = [4, 8, 12]
    change1(numbers)
    variable = [15]
    change2(variable)
    i = 0
    while i < 3:
        print numbers[i]
        i += 1
    print variable[0]

main()

test3.py: pass-by-reference example, changing a mutable data type list/table outside the main function

def change1(list1):
    list1[1] = list1[1] + 5

def change2(number):
    number[0] += 2

def main():
    numbers = [4, 8, 12]
    change1(numbers)
    variable = [15]
    change2(variable)
    i = 0
    while i < 3:
        print numbers[i]
        i += 1
    print variable[0]

main()

pass-by-value examples

test4.py: trying to find an example with pass-by-value, why it does not work?

$ cat test4.py 

# Not yet a pass-by-value example!

global variable
variable = [15]

def change1(list1):
    list1[1] = list1[1] + 5

def change2(number):
    number = [x+2 for x in number] 

def main():
    numbers = [4, 8, 12]
    change1(numbers)
    #variable = 15
    change2(variable)
    i = 0
    while i < 3:
        print numbers[i]
        i += 1
    print variable[0]

main()
$ python test4.py 
4
13
12
15   # I expected 17! Why no 17?
hhh
  • 50,788
  • 62
  • 179
  • 282

5 Answers5

2
def change1(list1):
        # `list1[1] =` means you are changing the object passed in
        list1[1] = list1[1] + 5

def change2(number):
        # `number = ` means you create a **new local variable**, number, 
        # based on the `number`you passed in
        number = [x+2 for x in number]

So if you want to change existing objects, you have to referene them in some way, for example in

def change3(number):
    # `number[:]` is the whole existing list and you overwrite it
    number[:] = [x+2 for x in number]

Note the [ .. ] when changing a list.

Jochen Ritzel
  • 104,512
  • 31
  • 200
  • 194
  • the reference is the key! The table does not change without reference even though being mutable data type. – hhh Aug 13 '11 at 13:31
  • 2
    @hhh: Call by reference or call by value are too primitive concepts to describe Python's semantics. If you want to change a object you have to use `obj[ .. ] = ` or `obj.attr = ` and similar, but not all values can be changed at all! What you really need to understand is that `obj` is neither a value, nor a reference, it's a name, a *instruction* for the Python VM to look up "obj" at runtime. – Jochen Ritzel Aug 13 '11 at 13:57
  • can you give an example of pass-by-value? I am still unsure what it means in Python. – hhh Aug 13 '11 at 14:00
  • 3
    Are you sure you know that call-by-value means in the first place? It's when the language creates a copy of the objects you pass. Python simply never does that, you have to be explicit and make the copy yourself. It's just that anything you do to a immutable value will return a new value with the change done. This may seem like the value was a copy to begin with (as in call-by-value), but that is wrong. As I just said, both these concepts don't really apply in Python. – Jochen Ritzel Aug 13 '11 at 14:23
  • are the examples above not examples of pass-by-reference? They still use reference and mutable data type. No, I have no idea what the concepts mean *academically*, I am just trying to interrept their apparent meaning (probably wrong). – hhh Aug 13 '11 at 14:41
  • 1
    @hhh: Passing a mutable object looks like call by reference. Passing something immutable looks like call by value. But Python does the same thing for all values - It simply aliases the value in the functions namespace (gives it a local name), with all the consequences this has. I call it call-by-aliasing for that reason. – Jochen Ritzel Aug 14 '11 at 11:24
  • "Are you sure you know that call-by-value means in the first place?" <-- look for newact's answer, contradicting yours. Who is right here? – hhh Aug 14 '11 at 16:31
1

Python parameters are passed by reference. You mutating only one object in change1.

However, numerical values and Strings are all immutable. You cannot change the value of a passed in immutable and see that value change in the caller. Dictionaries and Lists on the other hand are mutable, and changes made to them by a called function will be preserved when the function returns.

More: http://www.penzilla.net/tutorials/python/functions/

miku
  • 181,842
  • 47
  • 306
  • 310
  • why such design? Why to have immutable and mutable things? Why not just have everything as immutable/mutable? (would simplify things a lot or?) – hhh Aug 13 '11 at 13:25
  • 1
    Pass by reference will usually be more performant (imagine creating copies of large lists on each function call). Actually I think the quasi-symmetry of mutable and immutable data structures in python is quite useful. (More on pass by ref vs pass by value: http://stackoverflow.com/questions/373419/whats-the-difference-between-passing-by-reference-vs-passing-by-value) – miku Aug 13 '11 at 13:30
  • as for the pass-by-value, how can you do it in python? Notice how I tried it above (with a global but not working). – hhh Aug 13 '11 at 13:47
  • @hhh, you can't. But strings and numbers are immutable, so these kind of parameters will behave more as if you would actually pass them by value. – miku Aug 13 '11 at 13:49
  • is it a pass-by-value if I use "return value" with a function? – hhh Aug 13 '11 at 13:50
  • 1
    @hhh, pass-by-X usually discussed in the context of calls, not returns. – miku Aug 13 '11 at 13:52
1

The definitive answer is that Python is actually "call by sharing", also known as "call by object" or "call by object reference".

This has been extensively discussed before. From that article:

From time to time, people who’ve read a little CS but not a lot CS (or too much of just one kind of CS) pop up on comp.lang.python and waste a lot of energy trying to tell everyone that Python’s using some calling model that it doesn’t really use. It always turns out that they don’t really understand Python’s model, and quite often, they don’t understand their favourite model either.

But nevermind, the only thing you need to know is that Python’s model is neither “call by value” nor “call by reference” (because any attempt to use those terms for Python requires you to use non-standard definitions of the words “-value” and “-reference”). The most accurate description is CLU’s “call by object” or “call by sharing“. Or, if you prefer, “call by object reference“.

You should also read this, if you haven’t done so already.

Python's semantics are most similar to the semantics of the language CLU. The CLU Reference Manual by Liskov et al describes the semantics like this:

"We call the argument passing technique call by sharing, because the argument objects are shared between the caller and the called routine. This technique does not correspond to most traditional argument passing techniques (it is similar to argument passing in LISP). In particular it is not call by value because mutations of arguments per- formed by the called routine will be visible to the caller. And it is not call by reference because access is not given to the variables of the caller, but merely to certain objects."

Daniel Pryden
  • 59,486
  • 16
  • 97
  • 135
0

In change1 you exchange the value in the list with value + 5.
In change2 you add 5 to number. The result is a new object and is not just applied to the passed variable. If you come from C++: No there is no int& var in Python.

You get the expected result when doing this:

def change2(number):
    return number + 5

variable = 15
variable = change2(variable)

If you still don't want to return a value, you could create a MutableInt class.

class MutableInt(object):

    def __init__(self, value = 0):
        self._value = int(value)

    def __add__(self, other):
        self._value += int(other)
        return self

    def __sub__(self, other):
        self._value -= int(other)
        return self

    ...
Niklas R
  • 16,299
  • 28
  • 108
  • 203
0

All the examples show call-by-value. Python only has call-by-value. There is no call-by-reference. All values in python are references (it is not possible to have an "object" as the value). Hence it is references that are copied when passed to the function. Lists are mutable, so it is possible to mutate its contents through a shared reference. In change2 you are reassigning a local variable to point to another object, which, like all assignments to local variables, has no effect on any calling scope, since it is call-by-value.

newacct
  • 119,665
  • 29
  • 163
  • 224
  • contradiction with Jochen Ritzel's comment about call-by-value? – hhh Aug 13 '11 at 19:15
  • 1
    people just don't understand that values in the language are references, hence what you pass is a reference. the reference is copied, hence pass-by-value. it's not possible to do true pass-by-reference stuff (like swapping two variables in the calling scope) in python – newacct Aug 14 '11 at 07:46
  • "call-by-value, but all values are references" is just confusing. How do you explain "2+2" with this model? – Ned Batchelder Sep 01 '14 at 23:07
  • @NedBatchelder: Any expression, including `2`, evaluates to a reference. All operators, including the `+` operator, take operands that are references and returns a reference. The `+` operator invokes the `.__add__()` method, which on `int`s returns a reference to a number object that represents the sum of the two numbers that the operand references pointed to. – newacct Sep 02 '14 at 05:39
  • @newacct: to me, this sounds awkward. I'd like to be able to say that "2" is the value 2, and that "2+2" adds 2 and 2 together. Calling Python "call-by-value, but the values are references" is missing the forest for the trees. – Ned Batchelder Sep 02 '14 at 21:40
  • @NedBatchelder: If C++ had an extension that you could write integer literal `2` to mean `new int(2)`, of type `int*`, and the `+` operator were overloaded to take two `int*` and return an `int*`, and we describe it as such, would it be "awkward"? It's describing it as it is. That's what it is in Python. Any other way of describing it is either not consistent with the semantics, or makes up new terms that are equivalent to the already existing description. – newacct Sep 02 '14 at 22:39