Reputation: 453
I just realized that the pythonic swap doesn't always work.
def swap(x,y):
x,y = y,x
a = 1
b = 2
swap(a,b)
print b
result: 2
Why does the pythonic way to swap variables not work in this case? Do I need temporary a variable?
Upvotes: 2
Views: 804
Reputation: 78690
In the first line of the function definition
def swap(x,y):
x
and y
are so called formal parameters.
When you call
swap(a, b)
you are passing in a
and b
as actual arguments.
What happens now is that Python creates new names for the actual arguments you have passed in.
Inside the function body x
is now a new name for the integer object in memory which also has the name a
. y
is now a new name for the integer object in memory which also goes by the name b
. This is why Python is neither call-by-value nor call-by-reference, but best described as call-by-assignment.
Contrary to popular belief, calling functions and assignment works exactly the same way for mutable and immutable parameters. You will see the same behavior you are observing for mutable values:
>>> def swap(x,y):
... x,y = y,x
...
>>> a = [1]
>>> b = [2]
>>> swap(a,b)
>>> a
[1]
>>> b
[2]
So once you understand how assignments work in Python, you will also have understood how function calls work.
To make an example: If you did not write a function, your code would have been equivalent to:
a = 1
b = 2
x = a
y = b
x,y = y,x
del x
del y
In line 3, you are creating a new name x
for the integer object which also goes by the name a
. Line 4 follows the same logic.
In line 5, you are creating the tuple (y, x)
with the value (2, 1)
on the right hand side, which is then unpacked, i.e. the name x
is reassigned to the value 2 and the name y
is reassigned to the value 1:
>>> a = 1
>>> b = 2
>>> x = a
>>> y = b
>>> x,y = y,x
>>> x
2
>>> y
1
The important thing to note here is that a
and b
never stopped to be names for the value 1 and 2 respectively:
>>> a
1
>>> b
2
The last two lines just unbind the names x
and y
which is roughly equivalent to what happens in your function once you exit its scope. Note that the names a
and b
are still bound after unbinding x
and y
.
>>> a
1
>>> b
2
Upvotes: 4
Reputation: 15157
You never returned and assigned the results. Otherwise, as Joran said, you are only creating local variables in the function. For example:
def swap(a, b):
print "swap called"
return (b,a)
a = 1
b = 2
print a,b
a,b = swap(a,b)
print a,b
Results in the following being displayed:
1 2 swap called 2 1
Upvotes: 1