Functions
Overview
Functions are subprograms that package a sequence of program statements for execution when needed. A function must be defined before it can be used. Some of the functions are built-in functions that are already defined in Python and we can just use them. Others come from the standard libraries or libraries that can be installed using package managers such as pip. Here, we will see how we can define a programmer-defined function and what it means to return values from functions and call functions.
Defining functions
To define a function, we will need a way to tell the compiler that here is a definition of a function. This is done by using the keyword def
, which means define.
def square(x):
return x**2
The square function above is a programmer-defined function that is named square
(according to Python naming rules) takes a single parameter x
and returns x2. This is only the definition of the function. When we run the program above, nothing happens because we did not tell the CPU when and how to execute the function square
. To do that, we should call square
and supply it with a numeric value to get the square of that numeric value.
def square(x):
return x**2
value = eval(input('Enter a number: '))
print('Squared:', square(value))
In this program, we take a value
from the user and print value2 by calling square
. When executing the program above, the CPU starts the execution by asking the user for value
and converting it to a numeric type using eval
. Then, when executing print
, to get the value that must be printed, the CPU jumps to the execution of square
as specified by our program. Only at this time, the CPU fully executes square
, evaluates the expression ahead of the return
statement, and returns the result back to where the function was called. The returned result is then given to print
to be displayed on the screen.
Functions with no return
There could be functions that do not return anything. One such function is the print
function, which only takes its input arguments and displays them on the screen. For example, a statement such as x = print(1)
has no special effect beyond printing 1
on the screen. The variable x
will not contain any value after executing the statement. These functions have no return statement.
def f():
print('Hello and welcome to my program. Below are the instructions on how to proceed.')
f
is only used to print a message when needed. This is useful to only call f
to produce the message instead of repeating the message throughout the program. When we need to change the message, we only have to change the body of the function f
to include the updated message.
Rules for defining functions
These rules are true (except for some details that may not be important at the moment) when defining functions:
- You can define any number of functions in a program.
- A function has a name and can have any number of parameters.
- Function names follow the rules of variable names.
- A function may or may not return a value.
- Function body is not executed until the function is called.
- The values of function call arguments are copied to function parameters with numeric and string types.
- When a function call argument is a list, a pointer to the list is copied to function parameters. Changing the list inside the function changes the list in the caller.
A function to split a string
We're required to write a function that receives a string S
and a separator string sep
and returns a list by splitting S
according to the separator sep
. For example, given "hello-world"
as S
and "-"
as sep
, the function returns ['hello','world']
. This function works similarly to the split
method for strings.
To solve this problem, after understanding it, we must design a solution for it. Our design is realized in the following steps.
Assume L
is an empty list and T
is an empty string.
- For each character
c
inS
.
- If
c
is notsep
, add it to a temporary variableT
. - If
c
issep
, addT
to the listL
and resetT
to an empty string.
- Return
L
Our design is now ready to be translated to Python.
def split(S,sep):
L=[]
T=''
S+=sep
for c in S:
if c != sep:
T+=c
else:
L.append(T)
T=''
return L
Optional parameters
A function can have optional parameters. That is, parameters that have default values do not need to receive arguments from a function call.
from math import sqrt, inf
def f(x,y,a=inf,b=inf):
s,t = 0,0
if a < inf:
s = x+y*a
if b < inf:
t = x+y*2*sqrt(b)
return s,t,x+y
print(f(2,5))
print(f(2,5,b=4))
print(f(2,5,a=2,b=4))
In this program, a
and b
are optional parameters. If the call does not supply arguments for either a
or b
, they'd be assigned ∞. Otherwise, they will receive the value of the provided arguments. For example, in the first print, no value is provided for a
or b
. In this case, both are assumed to be ∞. In the second print, only b
has an argument while a
remains ∞. Finally, in the last print, both a
and b
receive values from the call.
Notice that this function can return multiple variables. The return
statement constructs a tuple with the value of s
, t
, and x+y
and returns it to the call. The value received by the call is a tuple and can be used accordingly.
Scope of variables
Python has a way to tell which variables are visible where. That is, if a specific variable name x
appears in multiple locations in the program, we'd like to know if each appearance points to a different location in memory. The scope of a variable determines when a variable is visible. This concept is directly related to functions. This is because a function creates a new scope in which we can reuse variable names from other scopes. This can be easier to understand with an example.
x = 10
def f(x):
x = 2
def g():
print(x)
def h():
global x
x = 4
g()
f(x)
print(x)
h()
print(x)
This program outputs 10 10 2. We can observe that x
appears in multiple scopes. First, x
is a global variable with a value of 10. This variable occupies a memory cell, which holds 10. Next, when we call g()
, we see that g()
can see the variable x
because x
is global. If g
had defined a variable with the same name, then g
would only see its own local copy, which we call a local variable.
Next, we see that calling f(x)
does not affect the value of the global variable x
. Although, f
appears to modify x
, since x = 2
is seen by the compiler as the definition of a new variable, then f
can only see its local variable x
, which points to a memory location holding 2, but cannot see the global variable x
, which points to a memory location holding 10. After that, we see that h
uses the keyword global
. This is used only when a function wants to modify the value of a global variable. In this case, the function declares that a variable is used as a global variable and can change its value using an assignment. This is why the last print
outputs 4 on the screen.
The basic scope rules are summarized below.
- A variable defined outside any function is a global variable.
- Each function can reuse the names of global variables for its own local variables.
- A function
g
can use the value of a global variable ifg
itself does not declare a (local) variable with the same name. - A function
g
can declare that a variablex
is global using theglobal
keyword. Then, any assignment tox
would change the value of the global variablex
.