Python function returns:

bruno at modulix onurb at xiludom.gro
Thu May 4 15:18:50 CEST 2006


Michael Yanowitz wrote:
>   I am still new to Python but have used it for the last 2+ months.
> One thing I'm still not used to is that functions parameters can't
> change as expected. 
>
> For example in C, I can have
>  status = get_network_info (strIpAddress, &strHostname, &nPortNumber)

You have to understand that Python and C are totally different beasts.

A C variable is mostly symbolic name for a memory address, tagged with
type infos. Assigning to a variable means storing a value at this
address. Reading a variable means retrieving whatever value is stored at
this memory address.

Python does not in fact have a concept of "variables". It has names and
objects. A binding is the association (in a hash table) of a symbolic
name (which is nothing more than a name) and a reference (read:
something like a smart pointer) to an object (which is itself a complex
data structure). So-called "assignement" (correct term is "binding")
'binds' together a name and a reference to an object. Except for some
special cases (mainly objects - which are they're own namespaces - and
when using the 'global' statement), this creates an entry in the current
namespace. Also, rebinding a name has no effect on other names bound to
the same object.

Function's params are bindings in the function's local namespace. This
means that the params *names* are local to the function. So rebinding a
param in a function won't have no effect on bindings in the caller's
namespace.

*But* - since many names can refer to the same object - *modifying* the
object referenced by a name will, well, modify this object, so this
modification will be visible everywhere.

ie (dummy example):

def appendToList(alist, what):
  alist.append(what)

mylist = []
appendToList(mylist, 42)
print mylist

What doesn't work as you'd expect is:

def failsToHaveSideEffects(alist, anything):
  print "before rebinding : alist = ", alist, " - anything = ", anything
  alist = anything
  print "after rebinding: alist = ", alist

mylist = []
print "before function call, mylist = ", mylist
failsToHaveSideEffects(mylist, 42)
print "after function call, mylist = ", mylist


So as you can see, it's quite possible for a function to *modify* it's
params - it's just rebindings of params that won't have side effects
outside the function's namespace.

Now, there is the case of immutable types (int, strings, tuples, ....).
As implied, one cannot modify objects of these types - just create them.
So in order to have a function that "change the value" of an immutable
object, you have to wrap it into a mutable object, ie:

def getAnswer(alist):
  alist[0] = "42"

answer = ["answer is ?"]
getAnswer(answer)
print "answer is : ", answer[0]

(snip)

>   In Python, there does not seem to be an easy way to have functions return
> multiple values except it can return a list such as:
> strHostname, nPortNumber, status = get_network_info (strIpAddress,
> strHostname,
>                                                      nPortNumber)
>   Am I missing something obvious? Is there a better, or more standard way
> to return values from functions?

This *is* the 'standard' (ie: idiomatic) way to return multiple values
from a function. The C idiom of passing pointers to variables that are
to be modified comes from C's limitations, namely no exception handling
and only one return value[1], which leads to using the return value as a
status report and relying on side effect for useful values.



[1] To be pedantic, Python only allows one return value too - but this
value can be a tuple or list, and then one can take advantage of
tuple/list expansions that allows multiple assignment...

HTH
-- 
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'onurb at xiludom.gro'.split('@')])"



More information about the Python-list mailing list