Expressions compute values and make those values available for
further use. Functions can also compute values and make those values
available for further use. They don’t have to do that, but they
can. For example, the sqrt
function returns a
value, which is the square root of the value of the actual parameter
passed to it. When a function computes a value that is available for
further use, we say that the function returns the
value.
Anywhere a value is needed, a call of a function that returns the right type of value (for example, an int, a float, a string, or a boolean) can appear.
For example, in a print statement, we can print the value returned by a function call:
Let’s dissect what is meant by “Anywhere a value is needed, a call of a function that returns the right type of value can appear.” Consider this line of code:
print( 8 + 12 )
Of course, this code outputs 20. Now, if we were to call
int(8.48528137423857)
, the value returned by the call of
int
would be 8, so let’s change the code to
print( int(8.48528137423857) + 12 )
Do you see what I’ve done here? We needed an int value as the left
operand of +
. Instead of 8, we used
int(8.48528137423857)
: a call to the int
function, which returns the value 8. Why did I choose
int(8.48528137423857)
? Because I’m going to go a step
further. The sqrt
function, when passed the actual
parameter 72, returns the float value 8.48528137423857. So we can change
the code to
print( int(sqrt(72)) + 12 )
We needed the value 8.48528137423857, and instead we used the
function call sqrt(72)
. Functions are called in the order
that their values are needed to compute the expression. So in this
example, sqrt(72)
calls the sqrt
function with
the actual parameter 72. The result 8.48528137423857
is
then made available. Then the result of calling int
is
needed, so the int
function is called, passing in the value
8.48528137423857
as a parameter. int
executes
and returns the value 8, which is made available. Finally,
8 + 12
is computed.
len
, int
, float
,
str
len
returns the length of a string, as an int value.
As we’ve seen, int
converts from some other type to an
int. If the number is a float, any part of the number to the right of
the decimal point is truncated (dropped). If the number is too large to
store in an int, Python returns a long int instead.
If you try to convert from a string that contains characters that
represent something other than a number, int
will fail and
your program will terminate. print(int("123"))
will work.
print( int("buffalo"))
will not.
float
and str
convert to float and string
types, respectively, and work as you might expect.
We can call the function randint
from the
random
module to get (nearly) random values. For
example:
This line prints a random integer between 5 and 20, inclusive. In other words, it’s equally likely to print any integer in the range from 5 to 20.
What if you want a random floating-point number? Call
uniform
, also from the random
module:
Objective: Make use of different results of a function call to take different actions.
Write a loop that simulates flipping a coin 5 times, and prints out
“heads” or “tails” after each flip. Use the Python randint
function to determine if the outcome of each flip should be heads or
tails.
Objective: Write a function that makes use of a different function you’ve written many times.
Write a function that draws n
smiley faces of random
size at random locations on the screen, where n
is a
parameter to the function. Click on the left arrow next to the
draw
function to unfold that function in the editor, and
call your function to draw 20 random smiley faces. You may assume that
the screen width and height are both 200. As a starting point, here is a
function to draw a single smile. Don’t forget needed import
statements.
When the value returned by a function is needed, the function is called. The current value of the program counter is saved. Then the program counter is set to the first line of the function. Python executes the body of the function. The function returns and the program counter is set to its value before the function call when one of two things happens:
Executing a return-statement does two things:
return
returns the value following return
(if any) to the calling code.return
immediately stops execution of the body
of the function and resumes execution at the point of call. That is, the
program counter goes back to just after the function was called.Here’s a really simple example.
As we now know, anywhere a value is needed, you can substitute an expression or function call that returns a value. For example, you could do something like this:
The line print( "I computed the value!" )
is
not printed on the screen, since the return-statement before
the print-statement will always immediately give control back to the
calling function by setting the value of the program counter. In fact,
Python will warn you that you have done something silly. Lines of code
that cannot be reached are called dead code. Normally,
you should not include dead code in a program.
Objective: Write a function that returns a value.
First, write a function circle_area51
that computes the
area of a circle of radius 51, and returns that area. Call the function
and print the result to verify that it works.
Then write a function circle_area
that takes a parameter
radius
, and computes the area o a circle with that radius.
Call the function three times, to compute the areas of circles of size
3, 5, and 51, and print the results.
Variables in Python are either local to a single function or global and accessible by any function. Python has some particular rules that determine whether a variable is local or global and how you access the variable.
When the first time you assign to a variable is inside a function, that variable is a local variable. A local variable is not accessible by any code outside the function in which it is defined. A local variables exists during that call of the function, and then it ceases to exist. You can think of local variables as disposable—use them in the function, and throw them away.
In this example, the variable x
is local to
some_function
. The line print( x )
within some_function
prints 4.
But the line print( x )
after the call to
some_function
is an error. That’s because the first time
that x
is assigned is within some_function
,
and so x
is local to some_function
. Therefore,
x
is not known outside some_function
.
Local variables:
Formal parameters are local variables, too.
We say that a local variable is in scope inside the function where it is created, after assignment.
Local variables are good. Most lines of code compute something, and store it in a nicely named local variable. Later lines of code use that variable to compute something else, and store it in a nice local. Using well-named local variables for intermediate computation is as important as commenting to make code understandable and modifiable by human readers.
The values of variables are stored in memory. Where? Each function call creates an area of memory called a frame to store values of the local variables that it creates. When the function is exited, the frame is destroyed, and the local variables are no longer in scope. This is good: the function is cleaning up after itself.
Every now and then, you want a variable to be available to many functions. Such a variable cannot be local, because a local variable is accessible only within the function in which it’s first assigned to.
A variable that is accessible by many functions is a global variable. Useful though may be, global variables also have their seamy underbelly, and so you should use them only when necessary.
Global variables are initialized outside of function definitions. If you are simply using the value of a global variable, you can access that global anywhere in any line of code (within the same file) that runs after the initialization of the variable.
Changing the value of a global variable is a big deal. Why? Doing so may affect countless other functions, some of which you might not even know about or have written. Where possible, you should avoid changing global variables, and Python forces you to explicitly tell it that the variable is global before using any assignment statements.
In any function where you want to assign to a global variable, you
must use the global
keyword to indicate that you really do
intend to change the value of the global variable. Here’s an
example.
Here, the function print_x
accesses the global variable
x
. Because x
has the value 5 when the function
is called, the assignment statement within the function assigns the
value 6 to x
, and both print statements print the value
6.
It’s important to remember that the keyword global
is
not needed to create a global variable. If you just intend to
make use of the value, you should not use the keyword global,
since the keyword makes it possible to change the value, and this could
affect any code that depends on the global variable.
What’s wrong with global variables? There are two obvious ways to get values into a function. The first is to use pass actual parameters into formal parameters; the second is to set a global variable that the function can use. If you choose the second, then
Although we’ll use some global variables for demonstration purposes, and there are even a few occasionally good uses of global variables, using a global variable should always make you very uncomfortable at the least. Frequently, you can wrap bare code inside a function, making variables local, and then pass the values of those variables into whichever function needs them.
Stylistically, using local variables and parameters to transfer data makes the flow of information clear throughout the program. Some function you want to use take some parameters; you think about what values you need and how to compute them. The function returns that value and you know you can use it. If the function uses or changes global values to get information in or out, it’s harder to see how to connect that function to other code.
There is one use of global variables that is fairly safe and, in fact, good programming practice: as named constants. For example, a chemistry program might use Avogadro’s number in several functions. If you typed the actual number in every time you used it in an equation, you might make a mistake, and it might be hard for a reader to figure out the equations, if they don’t recognize the number. A global variable can store the number, make it easy to change that number without searching and replacing, and makes the code more readable.
AVOGADRO = 6.0221415e23
We call global variables used to store values that don’t change constants. It’s good programming practice to type constants using all uppercase letters, so that they are recognizable as constants.
There are some built-in global variables in Python modules that you can use by importing them.
Notice that pi
is not capitalized in this case. The
capitalization is just a convention, and apparently the Python designers
didn’t use that convention. Bad Guido! (That’s Guido van Rossum, the
designer of Python, who is also known as The Benevolent Dictator For
Life.)
Although a global variable such as pi
imported from the
math library is intended to be constant, Python doesn’t prevent you from
changing it.
(I checked on the Internet about this story that the Great State of Kansas attempted to change the value of π to 3. Turns out it’s not true. Yay, Kansas!)
With great power comes great responsibility. Python lets you change the value of variables intended to serve as named constants. Don’t do it.
Consider the following code:
The test x == 5
evaluates to a boolean expression, as
must any test in an if-statement. This boolean expression must have
either the value True
or False
, right? And if
the boolean expression x == 5
has the value
True
, the function returns True
. If the
boolean expression x == 5
has the value False
,
the function returns False
.
In other words, the function returns exactly the same value
that the expression x == 5
evaluates to. So here’s another
way to write this function, which is shorter and more direct:
How does it work? We evaluate the expression x == 5
,
which comes to either True
or False
, and we
return exactly this boolean value. Notice that in either version of
is_five
, we return True
precisely when
x
equals 5, and we return False
precisely when
x
does not equal 5.
You should avoid code like the first version of the function. When you write code the first way, with an if-else-statement that just mirrors the value of a boolean expression, you are declaring to all the world “I don’t understand the boolean type!!!”