Today's Python lesson will cover a very important topic - functions. Writing
all the code straight in the global scope was all well and good for our small
educational programs which usually could only do a single thing. However,
consider writing a program which is thousands of lines long. I'm sure you agree
it'd be very hard to work with such a "noodle" of code if it was all in a single
file and a single logical block. Even more so, if we wanted to perform the same
command sequences at multiple places in our program. In this case, we'd have to
copy it all over again or to jump from one program place to another. Both
options are very confusing.

Functional decomposition

We sometimes refer to splitting a program into multiple functions as a
functional decomposition. Don't let the term intimidate you, we'll just think
about what our application needs to do and then create a function in our source
code for each of those tasks. In real-life applications, we usually create
auxiliary functions as well. For example, a function for printing the
application menu, or splitting a complex function to various simpler functions
to keep the program readable.

Functions are sometimes called subroutines or subprograms. If a function
doesn't return a value (more on this further along), it may be referred to as a
procedure in some programming languages. Functions for larger applications,
where there is a lot of them, are gathered into multiple modules/libraries. You
know these very well already, e.g. from writing import math which
loads the library (module) for working with mathematical functions. We'll also
learn to create said modules later on.

Creating functions

A function is a logical block of code which we write once and then call it
multiple times without needing to write it all over again. We'll declare
functions in the global scope, somewhere above our code. Let's add a function to
our source code which will write "Hi, welcome!".

We'll show the entire source code just to be illustrative:

#!/usr/bin/python3def greet():
print("Hi, welcome!")

We define functions using the def keyword. The empty parentheses
indicate that the function doesn't have any input parameters. As you can see,
the only thing the function does is printing text. Now, we have to call the
function to execute it. Of course, we'd only be able to do so after we declare
it, otherwise, the interpreter wouldn't recognize the function. Let's call the
function under its declaration:

Functions with parameters

A function can have any number of input parameters (they're sometimes called
arguments) which we write into the parentheses in its definition. We influence a
function's behavior by parameters. Consider a situation we want to greet our
users by their names. So let's extend our function of a name
parameter and specify it later with a concrete value when calling the
function:

The function's return value

A function can also return a value. Let's leave our greeting example and
create a function for computing the area of a rectangle. Furthermore, we'll make
it so we're able to use the result in other calculations. Therefore, we won't
write the result but return it as the return value. Every function can return 1
value using the return command which will also terminate the
function, so any other code after it won't be executed. We specify the data type
of the return value before the function definition. Add the following function
to your program:

In real-world applications, our function would probably compute something
more complex, so it'd actually be worthwhile to implement. However, as an
example, a simple rectangle will serve just fine. We name functions using
lowercase letters, whole words and using under_scores instead of spaces. Avoid
abbreviation names at all costs. For example, the birth_date()
function is much clearer than bird() which makes it hard to tell
what it even does at the first sight.

If we wanted to print the area of a rectangle now, we'd simply call our
function straight in the print() function. First, the rectangle's
area will be computed. Then, this value will be returned and passed as an input
parameter to print() which will print it. Let's try it out by
entering 10 and 20 cm as the width and height:

Console application
The sum of the areas of the rectangles is: 1000 cm^2

Regarding previous exercises we did earlier on in the course: you may try to
modify some of them and split them up into functions. According to good software
design practices, a source code should always be split up into functions (and
ideally into objects, more on this later on) to keep it clear. We omitted this
at the beginning to keep things simple, but now, please, keep this in mind

The main advantage of using functions is clarity and keeping code shorter (we
can write something once and call it a hundred times from multiple places in our
program). If we decide to modify the function, we would only have to do it at
one place and this change will affect all of the function calls immediately
which decreases the possibility of making an error, significantly. In the
greeting example, we could simply change the greeting text once in the function
and it'd affect all three of the calls. If we didn't have the code in a
function, we'd have to modify 3 sentences and it's very likely we'd make a typo
somewhere.

Positional and keyword parameters

Python supports 2 kinds of function parameters. We've just explained and
tried out positional parameters. We can also introduce
parameters which are distinguished by their names, not the
position in the parentheses. We call these parameters keyword
parameters, we have to declare them after the
positional ones and provide a default value for them so they won't need to be
specified. Let's create a simple example:

Keyword parameters are useful in situations when they do something special
and it'd be confusing to specify this behavior by simply passing a regular
positional parameter. They're even needed in cases where the function has a
variable number of positional parameters.

Variable number of parameters

A function can have a variable number of parameters, meaning we can pass as
many parameters to it as we need in an exact case. We use the *
operator to do so and we get all the parameters as a tuple.

Remember the print() function and it's end
parameter. We also use the sep keyword parameter to define the
separator between the print() parameters. The function accepts any
number of positional parameters and prints each of them.

{PYTHON}
print(1, 2, 3, sep="-", end="!")

The result:

Console application
1-2-3!

Recursion

To sum it all up, let's take a little peek into an advanced topic -
recursion. A recursive function is a function which calls itself in its body.
Such a function needs some information to determine when it should end.
Otherwise, it'd call itself, then it would call itself again, and this would end
the program terminating due to insufficient memory. Recursion is used very often
in various algorithms.

In functional programming languages, recursion is used instead of loops. For
example, a for loop that sums up the numbers from 1 to 10. We could
achieve the same result with recursion as well. The function would call itself
over and over with a number which increases by one 1 or it would terminate
itself (depending on what the current number is).

As you can see, reading code using recursion is not as easy as reading a code
using loops. However, that's not all. Using recursion creates additional memory
requirements since parameters and return values have to be passed over and over
again. Generally speaking, most programs which use recursion can be rewritten to
not do so. Let's create a sample program that computes a factorial. We'll make
versions with and without recursion.

You may run into recursion in existing source codes or at job interviews.
However, it's probably better to avoid recursion, at least for now. Recursion is
also able to waste the entire call stack quickly and terminate the program.
Furthermore, it's difficult to understand. If you're confused by it, you're
going to get more acquainted with it in the algorithms course where there's
enough room to explain it in further detail.

Well, that's all I've got for you in this course. If you'd like to learn more
about the Basic constructs of Python or feel like
you need more practice, take another look at the articles and lesson-specific
exercises. Our Python course will be continued in Basics of object-oriented
programming in Python. In the next lesson, we'll introduce you to an
object-oriented world. We'll get acquainted with many things that have been kept
hidden from us until now

The author is a programmer, who likes web technologies and being the lead/chief article writer at ICT.social. He shares his knowledge with the community and is always looking to improve. He believes that anyone can do what they set their mind to.

The author learned IT at the Unicorn College - a prestigious college providing education on IT and economics.