0

Does Python pass arguments to functions by reference or by value? I have heard that ints and chars are passed by value, but lists and strings are passed by reference.

But when I write-

def prepend(element,list):
    list = [element] + list

tryList = [1,2,3]
prepend(0,tryList)
print (tryList)

The expected output is (assuming that lists are passed by reference) is: [0,1,2,3]. But the actual output is: [1,2,3], which suggests that it is passed by value.

The main confusion arises when I write

def appendList(element,l):
    l.append(element)
tryList = [1,2,3]
appendList(0,l)
print (l)

output is: [1,2,3,0]

Abhishek Kedia
  • 867
  • 6
  • 17
  • 1
    All objects are passed by reference, but you re-bind the list. – Martijn Pieters Feb 10 '14 at 16:22
  • I suspect the actual output is `SyntaxError` since `try` is a reserved keyword. – roippi Feb 10 '14 at 16:25
  • @MartijnPieters: "objects" are not "passed" in Python because "objects" are not values. All values in Python are pointers to objects. – newacct Feb 10 '14 at 22:31
  • @newacct: that's all depending on what you define to be a value; I define the objects to be the values. Names are all just references. – Martijn Pieters Feb 10 '14 at 22:34
  • @MartijnPieters: You can say the exact same about Java, but the Java community would not agree with you. The semantics of assignment and passing Python and Java are exactly the same. – newacct Feb 10 '14 at 22:43
  • you can't update a variable's data directly in python, especially if it's a primitive like string or int, you can only reassign that variable and when you do, it gets reassigned according to the local scope, the parent variable that you think you're trying to update stays untouched. However, class instances are a different breed. If you pass the instance of a class to a function, you are premitted to modify it. So, when you call append on a list, you're modifying that list, which is a class instance, not a primitive per se. – KMA Badshah Jul 10 '21 at 09:14

4 Answers4

2

Python is PASS-BY-VALUE only.

Just like non-primitives in Java, all values in Python are references, i.e. pointers to objects. And just like in Java, they are assigned and passed by value. Always.

My definition is: If simple assignment (=) to a parameter has the same effect as simple assignment (=) to the passed variable in the calling scope, then it is pass-by-reference. If simple assignment (=) to a parameter has no effect on the passed variable in the calling scope, then it is pass-by-value. It is the latter in Java, Python, Ruby, Scheme, Go, C, JavaScript, Smalltalk, and many other languages.

newacct
  • 119,665
  • 29
  • 163
  • 224
  • @MartinPieters: My doubt is: while the local variable named "list" in the function prepend changes to [0,1,2,3] so why does the global variable "tryList" not change? – Abhishek Kedia Feb 11 '14 at 12:41
  • @coderkd10: What do you mean by "change"? If you mean the variable `tryList`, which is a pointer to an object, it does not change (point to anything different) because nothing assigns to it. If you mean the object that `tryList` points to is not mutated in some way, that's because nobody called anything on it to change it. The only use of that object is as an argument to a `+` operator inside `prepend`. However, in `appendList`, you called `.append()` on the object, a method that changes the object. – newacct Feb 11 '14 at 21:08
  • Readers I'd like to refer you to this post, its much clearer: http://stackoverflow.com/questions/11222440/python-variable-reference-assignment – Andrew S Apr 24 '17 at 00:10
0

list = [element] + list creates a new list and overwrites the original value of, um, list. I doesn't add element to the existing list so it doesn't demonstrate pass by reference. It is equivalent to:

list2 = [element] + list
list = list2

The following demonstrates pass by reference by adding to the existing list instead of creating a new one.

def prepend(element, _list):
    _list.insert(0, element)

_try = [1,2,3]
prepend(0, _try)
print(_try)

UPDATE

It may be more clear if I add print statements that show how the variables change as the program executes. There are two versions of prepend, one that creates a new object and another that updates an existing object. The id() function returns a unique identifier for the object (in cpython, the memory address of the object).

def prepend_1(element, _list):
    print 'prepend_1 creates a new list, assigns it to _list and forgets the original'
    print '_list refers to the same object as _try -->', id(_list), _list
    _list = [element] + _list
    print '_list now refers to a different object -->', id(_list), _list

def prepend_2(element, _list):
    print 'prepend_2 updates the existing list'
    print '_list refers to the same object as _try -->', id(_list), _list
    _list.insert(0, element)
    print '_list still refers to the same object as _try -->', id(_list), _list

_try = [1,2,3]
print '_try is assigned -->', id(_try), _try
prepend_1(0, _try)
print '_try is the same object and is not updated -->', id(_try), _try
prepend_2(0, _try)
print '_try is the same object and is updated -->', id(_try), _try
print _try

When I run it, you can see how the objects relate to the variables that reference them

_try is assigned --> 18234472 [1, 2, 3]
prepend_1 creates a new list, assigns it to _list and forgets the original
_list refers to the same object as _try --> 18234472 [1, 2, 3]
_list now refers to --> 18372440 [0, 1, 2, 3]
_try is the same object and is not updated --> 18234472 [1, 2, 3]
prepend_2 updates the existing list
_list refers to the same object as _try --> 18234472 [1, 2, 3]
_list still refers to the same object as _try --> 18234472 [0, 1, 2, 3]
_try is the same object and is updated --> 18234472 [0, 1, 2, 3]
[0, 1, 2, 3]
tdelaney
  • 73,364
  • 6
  • 83
  • 116
  • There is no pass-by-reference in Python. – newacct Feb 10 '14 at 22:31
  • @newacct - depends on which pedantic overloading of the term "reference" you are using. For instance, when _list_ is passed to the function, its _reference count_ is increased. I've found talking "pass by reference" is a great way to describe what's going on especially as it relates to C/C++ programmers who are thinking in terms of value verses pointer-to-value. – tdelaney Feb 10 '14 at 22:48
  • Okay, so you mention C/C++. Values in Python are semantically identical to pointers-to-objects in C/C++. When you pass a pointer, that is not called pass-by-reference in C/C++. – newacct Feb 11 '14 at 03:10
  • @tdelaney - I cannot understand that when I say *_list=list2* although the local variable *_list* changes the global variable *_try* does not change. But when I write *_list.insert(0,element)* *_list changes* (which is fine) along with that *_try* also changes(which is troubling me). Please clarify me on this. – Abhishek Kedia Feb 11 '14 at 13:07
  • @coderkd10 - A variable and the object that it points to are different beasts. It can be difficult to describe because objects are nameless entities - they are referenced by named variables or by other objects. _try and _list start off pointing to the same object. `_list = [element] + _list` creates a new object and reassigns _list, leaving _try pointing to the orignal unchanged object. `_list.insert(0, element)` updates the orginal object that both _try and _list point to. – tdelaney Feb 11 '14 at 18:55
-2

"CALL BY OBJECT" This should answer your question. http://effbot.org/zone/call-by-object.html

Mohan Raj
  • 21
  • 9
-3

It is not pass by value. Everything in python is pass by reference.

def prepend(element,list):
    list = [element] + list  # Here new memory is allocated for "list" ,
                              # note list is here a local variable. 

And please do not use 'list' as name of varible, it is a keyword for data type name.

Arovit
  • 3,579
  • 5
  • 20
  • 24