# | include: false
import numpy as np
import pandas as pd
256852) np.random.seed(
Functions (Need)
![](https://imgs.xkcd.com/comics/functional.png)
What to expect in this chapter
By now, you will be comfortable using functions (e.g. print(), enumerate()
). In addition, I hope you are satisfied with the idea that a function is just a chunk of code that does a specific conceptual task. There is also the advantage that you can treat a function as a black box and just use it without knowing exactly what is going on in it. Sometimes this is good because too many details can be detrimental; other times it can be unwise as you do not know how an output is generated.
In this chapter, I will show you how to craft your own functions. In addition to its practicality, the modularity of functions prompts us to think of solutions about modular solutions to problems.
1 User-defined functions
print()
is an example of an internal function in Python. You can also create your own functions. There are two ways to do this: named and anonymous.
1.1 Named Functions
Named functions that return
We define the function by using the keyword def
as follows:
def greeting(name):
if name == 'Batman':
return 'Hello Batman! So, nice to meet you!'
else:
return f'Hello {name}!'
The function’s name is greeting
and it accepts a single argument called name
. We can then use the function as:
"Super Man") greeting(
or
="Super Man") greeting(name
As with all structures in Python, notice the keyword def
, the colon (:
) and the indentation that demarcates the function’s code block. Notice also that I have used the keyword return
to get an output from the function. When Python sees a return
keyword it jumps out of the function with the return value. You can pick up the returned value by assigning it to a variable or even use it directly like:
=greeting(name='Super Man')
greetprint(greet)
or this works too:
print(greeting(name='Super Man'))
Incidentally, you can use return
only within a function.
I also like to point out that you can return almost anything! Here is an example of a function that accepts a list and returns the maximum, minimum and mean.
def basic_stats(numbers):
= np.array(numbers)
np_numbers = np_numbers.min()
my_min = np_numbers.max()
my_max = np_numbers.mean()
my_mean return my_max, my_min, my_mean
Here is how you can use it:
= basic_stats([1, 2, 3, 4, 5]) list_min, list_max, list_mean
Named functions that don’t return
A function does not have to return anything. A good example is print()
, which does something but does not return a value. You will often also need functions like these, for instance, to save data to a file. I will show you a few of such functions in later chapters.
1.2 Anonymous functions
Anonymous or lambda functions are suitable for short one-liners. Let me show you two examples.
-
This function accepts a single argument called
name
.= lambda name: f"Hello {name}!" my_short_function
We can use it like
="Super Man") my_short_function(name
A
lambda
function always returns the value of the last statement. -
The above example is not a very good ‘anonymous’ one because I have used a name! So let me show you another one where things are really anonymous.
Let’s say I want to sort the following 2D list.
=[[9, 0, -10], numbers8, 1, -11], [7, 2, -12], [6, 3, -13], [5, 4, -14], [4, 5, -15], [3, 6, -16], [2, 7, -17], [1, 8, -18], [0, 9, -19]] [
I can use the
sorted()
function for this. Here are three ways I can use it.# Sort by comparing the default key # (i.e., the 1st element) sorted(numbers)
[[0, 9, -19] [1, 8, -18] [2, 7, -17] [3, 6, -16] [4, 5, -15] [5, 4, -14] [6, 3, -13] [7, 2, -12] [8, 1, -11] [9, 0, -10]]
Notice that this sorting is based on comparing the first elements of the sub-lists.
# Sort by comparing a custom key # that uses the 2nd element (index=1) sorted(numbers, key=lambda x: x[1])
[[9, 0, -10] [8, 1, -11] [7, 2, -12] [6, 3, -13] [5, 4, -14] [4, 5, -15] [3, 6, -16] [2, 7, -17] [1, 8, -18] [0, 9, -19]]
If I want to use some other criteria, then I need to specify a
key
thatsorted()
can be used for comparison. As you can see, I have used alambda
function for this.# Sort by comparing a custom key # that uses the sum of the elements. sorted(numbers, key=lambda x: sum(x))
[[0, 9, -19] [1, 8, -18] [2, 7, -17] [3, 6, -16] [4, 5, -15] [5, 4, -14] [6, 3, -13] [7, 2, -12] [8, 1, -11] [9, 0, -10]]
This is really powerful as I can specify almost any criterion I like. For example, I can sort according to the sum of the elements of the sub-lists.
1.3 Optional arguments
Python allows us to make arguments to our function optional. To do this, we need to give the argument a default value so that it always has something to work with.
def greeting(name='no one'):
if name == 'Batman':
return 'Hello Batman! So, nice to meet you!'
else:
return f'Hello {name}!'
Now we can run this function without an argument, and it will still work without throwing an error.
greeting()
'Hello no one!'
For another example, let’s look at the documentation for print()
.
print ?
Docstring:
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file: a file-like object (stream); defaults to the current sys.stdout.
sep: string inserted between values, default a space.
end: string appended after the last value, default a newline.
flush: whether to forcibly flush the stream.
Type: builtin_function_or_method
You see that print()
can accept other arguments that are optional with default values. However, we can specify them if we like; here goes.
# Using default values
print('I', 'am', 'Batman!')
# Specifying an optional argument
print('I', 'am', 'Batman!', sep='---')
I am Batman!
I---am---Batman!
Remember:
- you can define your own functions,
- functions can have optional arguments,
- functions don’t always have to return anything.
1.4 The importance of functions?
An argument for functions
Now that you know a bit about creating functions, let me highlight why functions are a good idea.
Abstraction of details The most important benefit of functions goes beyond programming and relates to your ability to strategize. If you break up a complicated solution into modular chunks (i.e., functions), it becomes easier to think about it because you are not dealing with all the details all at once. As a result, it is easier to focus on your overall solution because you are not distracted by unnecessary information. This hiding of ‘stuff’ is called abstraction in computer science lingo. The concept of abstraction can be tricky to grasp. So, let me share an analogy related to driving.
A vehicle has many ‘abstracted’ systems, amongst which the engine is a good example. You do not need to know the engine’s details (e.g. electric, petrol, diesel, guineapig) to use it. You can use the engine of almost any car because you are not required to know what happens inside. This frees up your resources because you are not distracted by unnecessary details. Of course, there will be times when you want to know how an engine works to pick the best engine.
Reusability of code If you encapsulate a chunk of code in a function, it becomes straightforward to reuse it instead of copying and pasting at different places. This means your code will be shorter and more compact.
Maintainability of code With functions, your code is easier to change and maintain because you need only make changes in one place, at the function definition.
A word of caution
I have seen many instances where functions are abused; for example, by trying to do too many things or having too many arguments. They can also be overused. Having too many functions can make it difficult to read your code and also increase computational overheads. You will get a better feel for when to use functions with experience, but please bear in mind that functions can be misused.