Riccardo said:
Hi all!
How does Python pass arguments to a function? By value or by reference?
Both...
Err, no, none.
Well...
*Short answer :*
args are passed by ref, but bindings are local.
*Long answer :*
You first need to understand what 'variables' in Python are. They are in
fact just a symbol referencing an object. Think of a Python 'variable'
as an entry in a dict, the name of the variable (the 'symbol') being the
key and the reference to the object being the value (AFAIK, this is
exactly what they are).
You also need to understand the difference between mutable and immutable
objects. Strings, numerics and tuples are immutables. Which means that
you can not change them. When doing :
s = "Hello "
s += "World"
.... you are not modifying the string object bound to s, but creating a
new string object and binding it to s.
Now for the "By Val/By Ref" stuff... well, try this :
def my_fun(my_arg):
print "in my_fun, before rebinding my_arg: my_arg = %s" % my_arg
my_arg = "42"
print "in my_fun, after rebinding my_arg: my_arg = %s" % my_arg
the_arg = "Life, the Universe, and Everything"
print "before call to my_fun: the_arg = %s" % the_arg
my_fun(the_arg)
print "after call to my_fun: the_arg = %s" % the_arg
You should have somthing like this :
before call to my_fun: the_arg = Life, the Universe, and Everything
in my_fun, before rebinding my_arg: my_arg = Life, the Universe, and
Everything
in my_fun, after rebinding my_arg: my_arg = 42
after call to my_fun: the_arg = Life, the Universe, and Everything
So what ? are we passing args by value ? Well, retry with :
def my_fun_2(my_arg_2):
print "in my_fun, before appending to my_arg_2: my_arg_2 = %s" %
my_arg_2
my_arg_2.append("42")
print "in my_fun, after appending to my_arg_2: my_arg_2 = %s" %
my_arg_2
the_arg_2 = ["Life, the Universe, and Everything"]
print "before call to my_fun_2: the_arg_2 = %s" % the_arg_2
my_fun_2(the_arg_2)
print "after call to my_fun_2: the_arg_2 = %s" % the_arg_2
and what do we get ?
before call to my_fun_2: the_arg_2 = ['Life, the Universe, and Everything']
in my_fun, before appending to my_arg_2: my_arg_2 = ['Life, the
Universe, and Everything']
in my_fun, after appending to my_arg_2: my_arg_2 = ['Life, the Universe,
and Everything', '42']
after call to my_fun_2: the_arg_2 = ['Life, the Universe, and
Everything', '42']
Argh ! So what ? Is it by val or by ref ?
Ok, let's try a third test :
def my_fun_3(my_arg_3):
print "in my_fun, before rebinding my_arg_3: my_arg_3 = %s" % my_arg_3
my_arg_3 = ["42"]
print "in my_fun, after rebinding my_arg_3: my_arg_3 = %s" % my_arg_3
the_arg_3 = ["Life, the Universe, and Everything"]
print "before call to my_fun_3: the_arg_3 = %s" % the_arg_3
my_fun_3(the_arg_3)
print "after call to my_fun_3: the_arg_3 = %s" % the_arg_3
An you get :
before call to my_fun_3: the_arg_3 = ['Life, the Universe, and Everything']
in my_fun, before rebinding my_arg_3: my_arg_3 = ['Life, the Universe,
and Everything']
in my_fun, after rebinding my_arg_3: my_arg_3 = ['42']
after call to my_fun_3: the_arg_3 = ['Life, the Universe, and Everything']
err... Time for some explanation ?-)
When you call a function with an arg, a "local variable" is created,
which references the object passed as the argument. (well... an entry
with the formal parameter name as key and a reference to the object
passed in is created in the 'local' dict).
So, rebinding this local symbol does not impact the binding in the
caller's namespace - because the symbol lives in another namespace.
*But* - and if the object referenced is mutable of course - modifying
the object in the function... well, just modifies the object, because
it's the *same* object that is bound to ('referenced by', if you prefer)
both symbols (the one in the caller's namespace and the one in the
function's namespace). So yes, the object *is* modified when the
function returns.
(Of course, doing anything to an immutable object is just rebinding the
symbol, so it won't never have any impact outside the function. So don't
expect to have a function having side-effects on strings, numerics and
tuples args. The good news being that this is not necessary, since the
only reason to do so would be to return multiple values, and Python can
already return multiple values.)
Does it make sens to you ?-)
HTH
Bruno
(Ho, BTW, please read the fine manual - and this too :
http://starship.python.net/crew/mwh/hacks/objectthink.html)