0

I meet this problem when implementing my own swap() method with Python

def swap(a,b):
    temp=a
    a=b
    b=temp

list_=[5,4,6,3,7]
swap(list_[4],list_[2])

I expexted list_ to be updated with swap() call, since list_[4] and list_[2] are to be assigned new values during function call. However, list_ remains unchanged:

list_
   [5, 4, 6, 3, 7]

I misunderstand why swap function call is dealing with a copy. I don't want to add a list argument to my swap function nor return the list during swap() call since I want the method to be adaptable to other datastructures, like in

 swap(mat[0][1],mat[2,3])
juliomalegria
  • 24,229
  • 14
  • 73
  • 89
kiriloff
  • 25,609
  • 37
  • 148
  • 229

2 Answers2

8

You are off on how Python works:

list_=[5,4,6,3,7]
swap(list_[4],list_[2]) # this is absolutely the same as
swap(7,6)

Python fundamental concept is the use of names and values. When you write down a name in code it stands for the value attached to it during runtime. In this case list_[4] is a name that stands for the value 7.

When you want to change something you must use one of it's names. Here you want to change the list_, so you have to do this:

def swap(data, i1, i2):
    data[i1], data[i2] = data[i2], data[i1]

swap(list_, 4,2) # swaps list index 4 and 2
Jochen Ritzel
  • 104,512
  • 31
  • 200
  • 194
  • not sure why, but ive just tried your code on a python 2.5 shell and received weird results : `>>> def swap(data, i1, 1i2): ... data[i1], data[i2] = data[i2], data[i1] ... >>> listy = [1,2,3,4,5] >>> swap(listy,listy[0],listy[3]) >>> listy [1, 5, 3, 4, 2] ` why did it swap the elements at indices 1 and 4 ?? anyone care to explain? – WeaselFox Feb 05 '12 at 15:28
  • 2
    @WeaselFox: Same as in the OPs example: `listy[0]` is 1 and `listy[3]` is `4` so it swaps these indices. – Jochen Ritzel Feb 05 '12 at 15:52
  • Could also subclass built-in `list` type and add a `swap()` method which would have an initial `self` argument -- just sayin'. – martineau Feb 05 '12 at 16:23
  • 1
    @WeaselFox: pass 0 and 3, not listy[0] and listy[3] :) – Ambidextrous Feb 05 '12 at 17:36
5

python passes by value so swap does not affect the original list. just use

list_[4], list_[2] = list_[2], list_[4]
JBernardo
  • 32,262
  • 10
  • 90
  • 115
WeaselFox
  • 7,220
  • 8
  • 44
  • 75
  • 1
    looks better without both parentheses – juliomalegria Feb 05 '12 at 15:39
  • It's not correct that Python passes by value. Because if we pass a list, it's passed by reference. In fact it depends on the passing object being mutable or immutable. The more realistic approach is to treat variable names as tags as described [here](http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#python-has-names). – ovgolovin Feb 05 '12 at 17:02
  • The idea of sending 'by reference' which looks sometimes as sending 'by value': http://ideone.com/Ewebt – ovgolovin Feb 05 '12 at 17:17
  • @ovgolovin it is not quite clear with this approach why my list tagged list_ in argument is not affected when calling swap operation on its elements. And list is mutable structure: then what is different between passing mutable or non mutable argument structure? In both cases it does not affect the structure (with non mutable, may raise an exception) i keep JBernardo and julio 's answer anyway – kiriloff Feb 05 '12 at 18:07
  • 1
    @dlib In your question you send two integers to `swap`: `list_[4]` and `list_[2]`. Then you make some assignments inside `swap` which rebind the variables `a` and `b` to the new addresses in memory. So nothing is changed outside `swap` function. But if you send the whole list as a parameter to `swap`, as Jochen Ritzel did, you may change what is inside this list. If you look more carefully on the Jochen Ritzel's answer, you will see that he doesn't reassign `data` inside the `swap` function, so `data` is pointing to the list sent to the `swap` from outside. – ovgolovin Feb 05 '12 at 18:33
  • @ovgolovin: Python only passes by value, in the exact same way that Java passes only by value. All values in Python are references; and they are passed/assigned by value. See http://stackoverflow.com/questions/986006/python-how-do-i-pass-a-variable-by-reference – newacct Feb 06 '12 at 02:35
  • @newacct By in the other terminology it means that the variables are passed by reference. For example in C if the parameter is passed by reference, it effectively means the reference is passed by value (and if we want to change reference, we should pass a reference to the reference). And it's called passing by reference in C. The only difference that in C we should explicitly dereference the reference inside the function, and Python does it implicitly. – ovgolovin Feb 06 '12 at 13:49
  • @newacct A great link by the way. The **update** section in the question has a perfect explanation of the whole idea what happens when something is passed to the function. – ovgolovin Feb 06 '12 at 14:01
  • @ovgolovin: Sure, you can call it that way, but then according to your definition, to be consistent, C and Java, and pretty much any language, has pass-by-reference. But if you e.g. go to the Java community and say their language uses pass-by-reference for objects, you will get yelled at – newacct Feb 06 '12 at 23:47
  • @newacct If you don't make anything special, C passes variables by value (and make the copies of variables on passing them to the function). And passing by reference only happens when you are sending a pointer to the variable, which (the pointer) is passed by value. And because the new pointer (inside the function) is pointing to the same variable, it's called passing by reference. It happens in Python the same way. The only difference that Python makes all that automatically (while in C you have to dereference the reference to get the variable value). – ovgolovin Feb 07 '12 at 00:05
  • @ovgolovin: If you define pass-by-reference that way and you call C, Java, Python pass-by-reference, that is fine. However, to write a swap function the way the OP wants, you need something different -- what I call pass-by-reference: the ability to pass a variable just like you are passing by value, without explicitly taking address or doing anything special at the call site, but have the function be able to *assign* to (not just mutate) that variable in the exact same way that you can assign to that variable in the original scope -- few languages, including C++, C#, PHP, Perl, can do that. – newacct Feb 07 '12 at 04:35