6.3. Functions that Return Values¶
Most functions require arguments, values that control how the function does its job. For example, if you want to find the absolute value of a number, you have to indicate what the number is. The math module has a function for computing the absolute value of floating-point numbers:
In this example, the arguments to the math.fabs
function are 5.0
and -5.0.
Some functions take more than one argument. For example the math
module contains a function called pow
which takes two arguments,
the base and the exponent.
Note
Of course, we have already seen that raising a base to an exponent can be done with the ** operator.
Another function that takes more than one argument is the built-in
function max
.
max
returns the maximum of the two input arguments. The arguments
can be either simple values or expressions. In the last example, 33 is
returned, since it is larger than 1.
Furthermore, functions like max
, math.pow
, and math.fabs
all return values that can be used to build more complex expressions.
So an important difference between these functions and one like
draw_square
is that draw_square
was not executed because we
wanted it to compute a value — on the contrary, we wrote
draw_square
because we wanted it to execute a sequence of steps
that caused the turtle to draw a specific shape.
Functions that return values are sometimes called fruitful functions. In many other languages, a chunk that doesn’t return a value is called a procedure, but we will stick here with the Python way of also calling it a function, or if we want to stress it, a non-fruitful function.
Fruitful functions still allow the user to provide information (arguments). However, there is now an additional piece of data that is returned from the function.
How do we write our own fruitful function? Let’s start by creating a
very simple mathematical function that we will call square
. The
square function will take one number as a parameter and return the
result of squaring that number. Here is the black-box diagram with
the Python code following.
The return statement is followed by an expression which is
evaluated. Its result is returned to the caller as the “fruit” of
calling this function. Because the return statement can contain any
Python expression we could have avoided creating the temporary
variable y
and simply used return x*x
. Try modifying the
square function above to see that this works just the same. On the
other hand, using temporary variables like y
in the program
above makes debugging easier. These temporary variables are examples
of local variables, pursued further in the next section.
Notice something important here. The name of the variable we pass as
an argument — to_square
— has nothing to do with the name of
the formal parameter — x
. It is as if x = to_square
is
executed when square
is called. It doesn’t matter what the value
was named in the caller. In square
, it’s name is x
. You can
see this very clearly in codelens, where the local variables for the
main function and the local variables for the square function are in
separate boxes.
As you step through the example in codelens notice that the return statement not only causes the function to return a value, but it also returns the flow of control back to the place in the program where the function call was made. this is true in general:
Note
The call to a function terminates after the execution of a return statement.
Another important thing to notice as you step through this codelens demonstration is the movement of the red and green arrows. Codelens uses these arrows to show you where it is currently executing. Recall that the red arrow always points to the next line of code that will be executed. The light green arrow points to the line that was just executed in the last step.
When you first start running this codelens demonstration you will notice that there is only a red arrow and it points to line 1. This is because line 1 is the next line to be executed and since it is the first line, there is no previously executed line of code.
When you click on the forward button, notice that the red arrow moves
to line 6, skipping lines 2 through 4 of the function (and the light
green arrow has now appeared on line 1). Why is this? The answer is
that function definition is not the same as function execution. Lines
2 through 4 will not be executed until the function is called on
line 11. Line 1 defines the function and the name square
is added
to the global variables, but that is all the def
does at that
point. The body of the function will be executed later. Continue to
click the forward button to see how the flow of control moves from the
call, back up to the body of the function, and then finally back to
line 11, after the function has returned its value and the value has
been assigned to result
.
Function definitions include the return type of the function. The
return type is between the arrow, ->
and the the colon :
at
the end of the header. The square
function above returns a
float
. The type of the value that the function returns must match
the return type in the function header. If they do not match the
program will not run due to an error:
What’s the Deal with None?
You may have noticed that the main function always has the return type
None
and always returns the value None
. None
is a special
type in Python because the value None
is the only value with the
type None
. So strangely enough None
is both a type and a
value.
Functions that return None
, are non-fruitful functions. Even
though these functions do not return a value, other than None
,
they still must have a return type and a return statement. This is
why all of the examples in the previous sections end with return
None
.
Non-fruitful functions are called differently than fruitful functions. When calling a fruitful function something must be done with the return value. For example, trying to call a fruitful function like it is non-fruitful function will produce an error:
It is not an error to call a non-fruitful function like a fruitful function. But it will produce undesired output:
The above program prints both the greeting and None
. It prints
None
because that is the return value of the function.
Check your understanding
- You should never use a print statement in a function definition.
- Although you should not mistake print for return, you may include print statements inside your functions.
- You should not have any statements in a function after the return statement. Once the function gets to the return statement it will immediately stop executing the function.
- This is a very common mistake so be sure to watch out for it when you write your code!
- You must calculate the value of x+y+z before you return it.
- Python will automatically calculate the value x+y+z and then return it in the statement as it is written
- A function cannot return a number.
- Functions can return any legal data, including (but not limited to) numbers, strings, etc.
func-2-1: What is wrong with the following function definition:
def add_em(x: int, y: int, z: int) -> int:
return x + y + z
print('the answer is' + (x + y + z))