By the end of this lesson, you should be able to:
Functions are a powerful programming concept that makes a program design
modular. In a nutshell, a function is a group of statements. A
programmer can call and execute that group of statements through the
function name. That means once a useful function has been created (like
the built-in functions input
, type
, print
)
it can be called and executed multiple times from within a program. If
the function was designed well and it is generic enough, it can be used
across programs too.
Good programming practices suggest that a single function should perform one dedicated task. The function should be written using variables, rather than hard coded values so that it is generic in nature and can be reused effectively and easily.
We already know some built-in functions. Take input
as an
example. Users can provide a custom string to this function, which is
displayed on the console and the input
returns a user
entered value as a string.
Similarly print
can be used to output a varying number of
integers, floats, and strings. The order and combination can vary. Let's
think of the functions that we can make in our programs. Suppose we are
making a program to calculate employee salary. We will be expected to
design a program that does the following:
It seems that we might need two functions in this program (see Figure 1 ). The first function calculates the gross pay. This function use the number of hours worked and the rate of pay to calculate the salary. It then adds benefits like transport allowance to the salary and return back the data.
The second function takes the gross pay produced by the first function and makes necessary deductions. It can deduct provincial tax, federal tax, and union fees and return back the take home salary.
Modular programs are similar to long reports. Rather than having the entire report under a single heading, multiple headings are created and the content is divided in sections.
Functions have a lot of benefits and for that reason they are extensively used in programming to make source code modular. Some benefits are listed below:
There is no need to duplicate the code and write the same sequence of
statements multiple times. Once a function has been designed, it can
easily be called as many times as needed in a program. Functions can be
reused in other programs as well like you used print
and type()
in previous modules. For example, the function for the calculation of
gross pay (Figure 1) can be reused in another program being designed for
managing the payroll system of another company.
You do not need to try to solve the entire problem once. You can divide the program into sub tasks and solve each one separately.
Teams work together to develop applications. The need to read and use or modify a source code comes up quite often. Functions make code reading and understanding much easier. Code readability is also the reason why comments are encouraged in code. In this lesson we also discuss docstrings, which are used to document functions.
There is no need to solve the same problem multiple times. Also, different small tasks are solved in separate functions. Therefore, the code is simpler and is easier to modify or to enhance to add more functionality.
Modular design assists team work. Different team members can work on separate functions and later on the functions developed by various programmers can be combined together in a program.
Quality Assurance is a critical part of software development. Modularized programs help quality assurance engineers to do a better job. They test each function separately (unit testing) and make it part of the program. Any subsequent changes to a function requires retesting of a specific function. This helps pinpoint the origin of logical errors in the program.
In this lesson we start by writing simple functions. Functions also effect the visibility and behaviour of variables, which comes under the topic of scope. Afterwards we study how data can be passed to the function and how functions can send back data. We then discuss docstrings, which are used to document functions and also create custom modules.
We start by converting an existing program without functions into a program that uses a function. In Lesson 3 we wrote a simple program to convert a Fahrentheit temperature to celsius:
The important part of this program is the conversion from Fahrenheit to Celsius, and that is the part we are going to convert to a function. The input and output is not going to be part of the function as that is a separate concern - it is not the function's job to either get input from the user or to output the result.
A function must be defined in a PyDev module in the same way that the program above was defined in a module (t02.py, for example). For ease of reuse functions are generally defined in their own module, or library. (Function libraries were discussed in Lesson 3.) These libraries should not be in the same modules that use the functions, as is discussed later.
A function needs to have a distinct name. All the variable naming rules
(discussed in Lesson 2) also apply to functions.
We start by writing a function named f_to_c
:
The function has both similarities with and differences from the program referred to in Code List 1. The similarities are:
The differences are:
def
to tell
Python that this is a function.f_to_c
.
fahrenheit
from somewhere, and
that is as a parameter. Parameters are listed within
parentheses as part of the function definition.
celsius
result, it still has to give the rest of the program access to that
value, so it returns celsius
.def
statement. This is a Python
requirement!
Use:
), and
what the parameter and return values are.
Calling a function simply means that your code is going to
invoke, or ask the function to execute, by giving the function name,
provide it with appropriate parameters (if any), and capture its return
value(s) (if any). The following shows how to call the f_to_c
function:
This code breaks down as:
from
functions import f_to_c
f_to_c
.
This does not execute the function, it merely makes it available for
execution later in the program. This is the same approach used to
access functions from the Python math library.f_to_c
function with:celsius1 = f_to_c(37)
return variable(s) = function
name(parameter(s))
f_to_c
is captured i the variable celsius1
, and the value passed
to the function parameter list is the literal integer 37
.
celsius2
and
the value passed to the function parameter list is the variable fahrenheit
The point of this example is to illustrate that functions can be called in many ways. The only required consistency is that the number and type of parameters must match the function's required parameters. The names are irrelevant.
We can define multiple functions in a Python module. One function can call other functions. The ordering of their definitions does matter.
We are using variables in our programs. Values are assigned to the variables and then we can use the value using variable name. With the introduction of modular programming, an important question arises: Is every variable accessible in each function of the program or not?
Scope dictates the rules about the visibility of a variable in any function.
The following trivial example shows how the scope of the variable x
is determined by where it is defined:
This produces the output:
This sample output clearly illustrates that even though functions and the main code do not share the variables that they each declare.
This is a very artificial example used only to illustrate scope. We normally define functions in modules separate from the modules that call the functions, and we do not use global variables in this course. Thus situations like this do not often arise in our programming style.
We do use global constants, in the sense of defining constants
that can be used by many functions in the same module, or accessed by a
calling module like pi
from the math library, or FAHRENHEIT_FREEZING
from a previous example.
We have been showing examples of functions with parameters, but want to discuss them more formally in this section. Arguments and parameters are a way to pass data to a function. A function does not care where the values it processes come from so long as they are in the correct order and of the correct type. The values defined within the function are parameters, and the values that are passed to a function when it is called are arguments. There is a one-to-one correspondence between arguments and parameters. We will illustrate this with a simple function and call to that function.
This function takes two parameters:
and the code that calls this function:
This function and the call to it illustrate the use of parameters and arguments:
calculate_salary
are hours_worked
and pay_rate
. We know these
are parameters because they are listed within the parentheses of the
function definition ((hours_worked,
pay_rate)
), and because they are explicitly referred to as Parameters
in the function documentation.
float
values. (Note
that the function does not have to enforce the constraints, just that
the function promises to calculate a useful total salary only if the
constraints are met.)
hours
and rate
. When the function is called, as in Line 5 of
Code Listing 2, the value in the argument hours
is passed
into the parameter hours_worked
, and the value in the
argument rate
is passed into the parameter pay_rate
.
Note that:
The output for a sample run of the given program is:
Note that it was not the job of the function to print the results - that was up to the program that called the function and captured its return value. Return values are discussed in detail in the next section.
A return
statement is used to send data from a function to
whatever calls that function. For example, the built-in input
function returns the value entered by the user. This value is assigned
to the variable before the assignment operator. See the first line of
code below:
We have used the input
and float
functions
before, but what is actually happening here?
input
is
executed and it takes a value from the user as input. The variable student_name
then captures the returned value by assigning the result of the
function call to the variable.input
function returns a
value that becomes the argument for the float
function.
The variable cost
then captures the value returned by float
.
We have already seen the f_to_c
function, and how it accepts a Fahrenheit temperature parameter and
returns a single celsius value, and how the calling code provides an
argument to the function and captures that single returned value in a
variable.
Python functions may return zero, one, or many values in their return
statements. The following function takes five parameters and returns
three values:
The function calculates and returns three values. The return
statement names those values in a comma-separated list.
Sample code to call the function:
This code calls the function and passes it the required parameters.
And the results of executing the sample call:
We discussed the importance of comments in programming. A docstring is a Python method of commenting that documents functions and modules. There are a few variants of docstring styling, but the objective is the same for all of them. Docstrings provides the following information about a given function:
Use:
).
Parameters
).
(int > 0)
. The function does not have to enforce
this constraint - this merely informs a user of the function of what
has to be true about the parameters in order for the function to
guarantee that it produces valid results.
Returns
).
The following is an example of docstring for the stat function:
This docstring tells us that the function:
total, average,
max_val = stats(no1, no2, no3, no4, no5)
float
float
Modules or libraries are collections of functions that
can be used in multiple programs. Earlier you have worked with the
built-in math
module. This module contains a wide range of
basic mathematical functions and constants.
Similarly, when making larger programs you should organize your own code into modules. If creating a payroll application, all the functions that deal with taxes and deductions can be in one module, whereas all the functions that produce reports and data for the management can be in another module.
A module is simple to create. It is just a collection of functions and/or constants. The following is a sample module, energy.py:
This module contains two functions and one constant, and uses another module (the math module) to perform its calculations. The entire module begins with a docstring and each function contains it own docstring. Note that the constant is defined at the beginning of the module and can therefore be used by all functions within the module as necessary, and be available for import into another module.
Importing and using this module is done the same way as importing and using the math module, as in this example:
This program imports and executes two of the functions in the energy module, and also imports and prints the acceleration due to gravity constant. This constant could be used in further calculations if necessary.
Modularity is key to organized and efficient program design.
In this lesson we learned about modular programming. It is a powerful
concept to make large programs manageable and well organized. We started
by creating void functions. Later on, we discussed scoping, how we can
pass data to the function using arguments, and how we can get data back
from the function using the return
keyword. In the last two
sections, we covered function documentation and the use of modules.