Consider this little program.
import math
def sq(x):
return x ** 2
def f(x):
sinx2 = sq(math.sin(x))
x2 = sq(x)
return sinx2 / x2
print(f(0.1))
Here is the order in which this program executes.
f
with x
being 0.1.f
function first computes sin 0.1 ≈ 0.0998,
then passes that to sq
.
sq
with x
being 0.0998.sq
function returns the square of that, 0.009967.f
function saves this result, 0.009967, into
sinx2
.f
function passes x
to sq
.
The question is… what is x
now?
In entering sq
, we just set x
to be 0.0998.
However, that was sq
's x
; f
has its own
x
, which has never changed from 0.1. Since f
is
passing its x
, the number 0.1 is passed to x
.
sq
with x
being 0.1.sq
function returns the square of that, 0.01.f
function saves this result, 0.01, into
x2
.f
computes the ratio of sinx2
and
x2
, 0.9967, and returns that result.The important point here is that each function has its own
“world” of variables.
When sq
stashes something into one of its variables,
it has no effect on variables in f
's world, even if the
variables happen to share the same name.
There is an exception to this: Variables that exist outside any functions are available to all functions. These are known as global variables, for obvious reasons. For example:
pow = 5
def sq(x):
return x ** pow
Here, the sq
function refers to pow
. This
variable doesn't exist within its own “world,”
so Python looks to the global variables and finds that pow
is 5.
However, if sq
had any code that wrote to
pow
(i.e., “pow = y
”),
Python would conclude that sq
has its own pow
variable,
separate from the global pow
.
In practice, this is rarely an issue. (But if you wanted sq
to actually change the global pow
, you could do that by
inserting a special statement “global pow
”
into the sq
function.)
In practice, expert programmers disdain global variables, except for circumstances where the global variable is a constant: That is, where the variable's value never changes from its initial value, in which case the variable is just an alternative name for that value.
Sometimes we want functions that don't return anything.
Such functions exist purely for their side effects:
Usually, the function displays something.
The built-in print
function is a significant example.
For example, suppose we want a function that displays a muliplication table for the numbers 1 through the parameter value.
def print_table(n):
for i in range(1, n + 1):
line = ''
for j in range(1, i + 1):
line = line + ' {0:3d}'.format(i * j)
print(line)
print('multiplication to 3')
print_table(3)
print('multiplication to 5')
print_table(5)
This function lacks any return
statement.
When the program calls
“print_table(3)
”,
the function displays the multiplication table
and then reaches the function body's end. At that point, it
would return, and the calling code would go on to the next line,
“print('multiplication to 5')
”.
Suppose somebody were to write
“x = print_table(3)
” for some
reason. Since print_table
ends without returning
anything, x
would get a useless value (namely, None
).
In practice, nobody would ever try to use the value from a
function that doesn't return anything.
By the way, one sometimes wants a return
statement
that exits the function without having the function return
anything. This is easy enough: Just write “return
”
with nothing following it.
def show_sum(pow):
total = 0
while True:
line = input()
if line == '':
print(total)
return
total += float(line) ** pow
In this case, when the function is called,
the function reads several lines from the user, adding the
values on the lines. But when the user finally enters an empty line,
the function displays the current value of total
, and
then the function ends its computation.