[Tutor] trying to understand the logic of functions

Brian van den Broek bvande at po-box.mcgill.ca
Tue Mar 23 13:05:43 EST 2004


Date: Mon, 22 Mar 2004 20:47:48 -0800 (PST)
From: python_simpleton <python_simpleton at yahoo.com>
Subject: [Tutor] trying to understand the logic of functions

> Q. return is "returning" a value (i guess that is what it is
> sup to do) but where does it return a value, what is the value
> and where is it going.

Hi all,

<Disclaimer>
I'm fairly new to Python and programming myself. This is my first
venture into responding rather than asking. So, take what I say
with a grain of salt rather than as the truth. And watch the list
for follow-up posts saying "that Brian guy is so wrong!" Also,
this may be a bit long, but I sorted these issue out for myself
recently enough that I recall where the newbie stumbling blocks
are. Last, sorry for thread breaking -- I'm switching off digest
so it won't happen again.
</Disclaimer>

Mathematically, a function is something that takes some input
values and produces an output value. Python functions are more
general. They take input values (possibly the empty input) and do
stuff, possibly producing an output value as well. It can be a
little confusing because the stuff done can look like the function
has produced an output value when strictly speaking it has not.

Consider the following

>>> def redundant_print(z):
	print z

>>> redundant_print(42)
42

It might look like the redundant_print function has produced 42 as
a output value, but really the function just ran a print instruction.

>>> 42 == redundant_print(42)
42
False

This prints 42 as per the function's instruction and then produces
'False' because 42 is not the same as the function redundant_print.

Now consider

>>> 0 == redundant_print(42)
42
False
>>> redundant_print(42) == redundant_print(42)
42
42
True
>>> redundant_print(42) == redundant_print(13)
42
13
True
>>>

The first is false because 0 is not the same as the function. The
last 2 both print the value passed into the function on the left,
then the value passed into the function on the right (because the
functions say to print that value) and then produce "True" because
the functions are the same. (The functions are evaluated for
whether they are the same function, and the difference of input in
the third case doesn't change the fact that the redundant_print
function is the redundant_print function.)

Now try

>>> def redundant_print_with_return(z):
	print z
	return z

>>> redundant_print_with_return(42)
42
42

This prints 42 as per the function's instruction and then, as the
function ends, returns ("sends back") 42 as the output. Since no
instructions were given for what to do with the output, it is
printed; thus the two output lines. (The first from the function's
print instruction, the second from the return statement.)

Now try

>>> 42 == redundant_print_with_return(42)
42
True

Again, it prints 42 as per the function. Having done that, the
function returns 42 as the output. This returned 42 then plays its
role in the expression that called the function. Since 42 equals
42, the expression 42 == redundant_print_with_return(42) produces
'True'. (The difference between this and the previous case is that
this time we gave Python something to do with the returned value
-- compare it to 42.)

Returns are needed to get values out of a function by ways other
than print or write to file instructions, etc. in a function. (I
ignore the yield statement here as I'd likely mess the explanation
up.) Consider what happens if you run the following script:

x = 42
def multiply_by_2(x):
	print x
	x = x * 2
	print x
multiply_by_2(x)
print x

It produces the following:

42
84
42

Why? The script assigned 42 to x, then defined the function, and
ran the function with x as input. The function prints its input
(which it calls x) hence the first 42. Then it doubles its input
and prints the result, hence the 84. Then, after the function ran,
the print x produced 42 when you might have expected it to produce
84. After all, the function reassigned x, didn't it? Nope. The
function reassigned the function's local version of x. The
function has a different namespace from the script itself. So, the
final print x statement says "print the script's version of x" and
that was assigned 42 and never reassigned. By contrast, the
function's print x statement say "print the function's version of
x" and that was reassigned within the function.

If you wanted the change to x within the function to be reflected
outside the function you could make the name global (I'd surely
get the details of this wrong if I tried to explain given my own
level of understanding, so I defer). Or, you could use a return
statement. Try this script:

x = 42
def multiply_by_2(x):
	print x
	x = x * 2
	print x
	return x
x = multiply_by_2(x)
print x

This produces:
42
84
84

Why? Again, x is assigned 42 it the script's namespace, and x is
passed into the function where, in effect, the value of the
script's x is assigned to the value of the function's x. (The two
x's being distinct as they "live" in different namespaces.) The
final line of the function returns the value of the function's x
(which at that point is 84). The return means that
multiply_by_2(x) (x here again being the x from the script's
namespace) serves as a name for the value of what the function
returned (84 in this case). So, "x = multiply_by_2(x)" is a
statement reassigning the script x to the value returned by the
function. The tricky bit here is that the script's x appears on
both the left and the right. But, as always in Python, assignment
statements evaluate the right hand side before assigning that
value to the left hand side. (This is just as x = x * 2 works.)

So, the returned value goes to the context that called the
function. In the first return example above the context was empty
in that all it was was a function call. So the returned value was
dealt with by the default process. The default is printing the
value, much like how typing 42 at the interactive prompt has the
same effect as typing "print 42". In subsequent cases the function
was called within a larger context (assignment statements in the
cases I gave). So, the returned value plays its role within those
assignments.

So, that was a lot of text! Hope it helped some.

Best to all,

Brian vdB








More information about the Tutor mailing list