So far we have dealt with some of the functions built into Python 3. We haven't touched all of the functions yet (we haven't dealt with for loops, the while function, slicing, file operations, etc.), but even with all of these functions, we are somewhat limited in what we can do with them. So, to supplement Python's abilities, we can do the following things:

a) Define functions that do a specific thing.

b) Import modules that extend the capabilities of the code.

Now modules may consist of many classes(*), each of which may have one or more functions. Hence, we will use this section to discuss about functions, how one may write a function, and a few examples.

Functions:

A function in Python isn't exactly like a function in mathematics (where you take a number, perform something on that number, and then get another number back). Rather, it's a block of organized code that performs a single action. There are two types of functions:

a) Built in functions - which we have been exclusively using so far

b) User defined functions

Now, the syntax for a function is the following:

Code:

def name_of_function(args):
"doc string"
code that the function should run
return something

Let's go through each of these items in turn:

* All functions must start with the keyword "def". This is then followed by the function name, and then a set of parentheses and a colon after the parentheses.

* Within the parentheses, we include all of the arguments that the function is allowed to take. It is possible to have a function that takes no arguments. We will cover the types of arguments in a moment.

* After the colon, an indented block starts. The next thing, which is optional, is the doc string. Usually this is encased in triple quotes. Also, this should hopefully tell the user what the function does.

* After the doc string comes the meat of the function. This is where the code that the function should run goes. This can be very simple, or it can involve very complex things with multiple loops.

* Once done, the function must include a return expression. The return expression may have 0 or more arguments. If it has 0 arguments, it is interpreted as return None.

Let's do a simple example now, before we move to recursive functions and a more detailed view of arguments.

Sum function:

This function takes two integers, a and b, and returns the sum of the two:

Code:

def sum(a, b):
return a+b

Now if we type

Code:

a = 1
b = 3
sum(a, b)

and execute in a new cell, we get 4, as we expect.

Recursive functions, and an example:

A recursive function is a function whose value is based on a previous value of the function. A couple of examples of these include:

* The Fibonacci sequence (0th term is 0, first term is 1, nth term is the sum of the previous two terms)

* The Lucas sequence (similar to the Fibonacci sequence but the first two terms are 2 and 1)

* The factorial function (0! = 1, 1! = 1, 2 = 2*1 = 2*1!, 3 = 3*2*1 = 3*2!, etc., so that n! = n*(n-1)!)

In Python, recursion can be done, by calling the function within the function with a different argument(**). To see this in action, let's code up the factorial function:

Code:

def factorial(n):
#Computes the factorial of a positive integer
if n < 0:
raise ValueError("n must be zero or a positive integer")
elif n == 0:
return 1
elif n == 1:
return 1
else:
return n*factorial(n-1) #see the recursion!

Try this on the following n's:

0 - should get 1

1 - should get 1

3 - should get 6

.2 - should get an error as after the first recursion, n-1 = -.8 which is smaller than 0.

More on arguments:

As stated above, we stated that we have arguments within the parentheses for functions. There are 4 types of arguments:

*Required arguments

*Keyword arguments

*Default arguments

*Variable length arguments

A required argument must be placed in correct positional order. The number of arguments in the function call must match exactly with the way we defined it.

Going back to our function sum(a, b), we see that the sum function must take 2 arguments when we call it. If we don't have that many arguments, then we get an error.

If we go back to the cell that we defined a and b and we remove the b in the sum, we get the following:

Code:

TypeError: sum() missing 1 required positional argument: 'b'

Keyword arguments are related to the function call. When a keyword argument is used, the interpreter will identify the argument by their name. As such, we can put them out of order.

For example, in a cell after you ran the cell with the sum definition, run this:

this should yield 9.

Default arguments: These specify a default value for an argument that will be used if the argument is skipped.

Variable length arguments:

In some functions, you may find it useful to have a function that takes more arguments than you defined. These are known as a variable length argument, and these are not named in the function definition, like so:

Code:

def name_of_function([args], *var_args_tuple):
"doc string"
code that the function should run
return something

the * before a variable denotes a variable that holds all the nonkeyword variable arguments.

Lambda:

Lambda can be used to run an expression, but not a command or multiple expressions. I haven't used these, but they may prove useful to you (***).

The syntax is the following:

Code:

lambda [args]:expression

where args is a comma separated list of arguments. There can be as many arguments as you like.

Lambda is also limited to using only variables that are declared globally, declared within the class (if it is a class) or those in the parameter list.

(*) Classes are used to define an object and the properties of all objects that are in the class. This has a clear analogue to C/C++ classes. As this requires more things to come together, we will cover this later.

(**) Care must be taken that you don't write a function that doesn't terminate.

(***) This is no longer the case. I used this to make a simple parse function that reads the data from

wttr.in for a qtile config.