For efficiently programming with Python, we need to learn how to write functions. In this article we will be familiar with basic of function programming in Python 3 and learn about some Python’s built-in functions through several examples. As a prerequisite for this tutorial, it is better to learn the following first:

The following is a good resource to learn more about function programming subject:

We can use Python to define any function that we want. A function should include:

**name**, to be able to refer it later**documentation**, to explain the function (optional)**parameters**, that could be zero or more**body**, that contains all computations that the function is doing

In general, we can use `def`

command to define functions like:

For example:

In general, we can define three types of functions:

**computative**, find the results by substituting parameters and doing calculations**iterative**, find the results by iteration (control flow tools)**recursive**, find the results by recursion (function itself)

In above example, we used a **computative** function to find *a * b*. Now let’s use **iterative** method:

```
def mult_itr(a, b):
"""
Two integers multiplication by iteration.
Note that a * b is equal to a + a + ... + a; b times.
"""
result = 0
while b > 0:
result += a
b -= 1
return result
mult_itr(12, 13)
## 156
```

We can also use **recursive** method such that:

```
def mult_rec(a, b):
"""
Two integers multiplication by recursion.
Note that a * b is equal to a + a(b-1).
"""
if b == 1:
return a
else:
return a + mult_rec(a,b-1)
mult_rec(12, 13)
## 156
```

At each iteration, both iterative and recursive functions follow this pattern to find *12 * 13*:

For another example let’s compute an integer factorial with all mentioned methods:

```
def fact(n):
"Compute n factorial by using Python math library"
import math
return math.factorial(n)
fact(6)
## 720
def fact_itr(n):
"""
Compute n factorial by iteration.
Note that n! is equal to n(n-1)(n-2)...1.
"""
result = 1
while n > 1:
result *= n
n -= 1
return result
fact_itr(6)
## 720
def fact_rec(n):
"""
Compute n factorial by recursion.
Note that n! is equal to n(n-1)!.
"""
if n == 1:
return n
else:
return n * fact_rec(n-1)
fact_rec(6)
## 720
```

Each of the above method has their pros and cons. For instance, let’s try a function that returns numbers in Fibonacci series:

```
def fib(n):
"""
Function to return nth Fibonacci number.
By using Binet's Fibonacci number formula.
"""
phi = 5**0.5
if n < 2:
return n
else:
return ((1+phi)**n - (1-phi)**n)/(2**n * phi)
[fib(x) for x in range(12)]
## [0, 1, 1.0, 2.0, 3.0000000000000004, 5.000000000000001, 8.000000000000002, 13.000000000000002, 21.000000000000004, 34.00000000000001, 55.000000000000014, 89.00000000000003]
def fib_itr(n):
"""
Iterative function to return nth Fibonacci number.
Note that Fibonacci series is 0, 1, 0+1=1, 1+1=2, 1+2=3, 2+3=5, ... .
"""
series = []
a, b = 0, 1
while len(series) < n:
series.append(a)
a, b = b, a + b
return a
[fib_itr(x) for x in range(12)]
## [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
def fib_rec(n):
"""
Inefficient recursive function to return nth Fibonacci number.
Note that Fibonacci series is f(n-2) + f(n-1).
"""
if n < 2:
return n
else:
return fib_rec(n-2) + fib_rec(n-1)
[fib_rec(x) for x in range(12)]
## [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
```

Here, computative method provides an estimation (which is actually a very good estimation) of the Fibonacci number and recursive method requires a lot of time as *n* gets bigger since at each iteration it needs to compute two `fib_rec`

such that (for *n = 5*):

```
fib_rec(5)
_______|________
| |
fib_rec(4) fib_rec(3)
___|___ ___|___
| | | |
fib(3) fib(2) fib(2) 1
__|__ __|__ __|__
| | | | | |
fib(2) 1 1 0 1 0
__|__
| |
1 0
```

Therefore, it is very important to always choose the right approach based on the function context.

Python provides another method that let us to write functions in a very compact way that called **lambda** function.

Python includes a quick one-line construction of functions that is often convenient to make your code compact. In general we can write lambda function such that:

For example:

Which is same as:

For another example, let’s find Euclidean norm of a vector by a lambda function:

```
pnorm = lambda v, p = 2: sum([abs(x)**p for x in v])**(1/p)
## Example
v = [2,3,4]
pnorm(v)
## 5.385164807134504
pnorm(v,1)
## 9.0
```

Or for instance, let’s replace an string in a mathematical formula with a number and find the answer:

For last example in here, let’s define single limit formula to find the second derivative of *f(x) = x^3* for *x = 2* by using **lambda**:

```
def deriv2nd(f, x, h = 1E-6):
"Single limit formula."
return (f(x-h) - 2*f(x) + f(x+h))/float(h**2)
f = lambda x: x**3
deriv2nd(f, 2)
## 12.002843163827492
```

As we know, the second derivative of *f(x) = x^3* is equal to *6 * x* which is equal to *12* for *x = 2*. Note that we can find the derivative of functions by using `SymPy`

package, for example:

Map and filter are two Python built-in functions that let us to expand our function programming tools. In general, **map** function is:

When a *function*, that could be another built-in function or a created function by **def** or **lambda**, applies on each element of an *iterable* (i.e. lists, tuples or dictionaries - see here to learn more). For an example let’s assume we have sales rate for each month during each season of a year and are interested to know what is the total seasonal sales:

```
sale = [(1,3,4,5),(3,4,5,6),(7,6,5,5),(8,6,9,1)]
seasonal = list(map(sum, sale))
seasonal
## [13, 18, 23, 24]
```

We can answer the above question without using **map** by:

```
sale = [(1,3,4,5),(3,4,5,6),(7,6,5,5),(8,6,9,1)]
seasonal = []
for i in sale:
seasonal.append(sum(i))
seasonal
## [13, 18, 23, 24]
```

As you can see, without **map** we need a loop to address each element of the *iterable*.

For another example, let’s assume we have an *iterable* of strings (e.g. a list of names) and want them to be in lowercase:

```
fruit = ['APPLE','ORANGE','PEACH','BANANA']
list(map(str.lower, fruit))
## ['apple', 'orange', 'peach', 'banana']
```

Or we can use **map** to round a list of float numbers:

Note that the above function has two *iterables* (`flt`

and `[2,2,2,2]`

).

We can also use **map** to create new functions. For instance, let’s define `zip_diy`

function that do same operation as Python `zip`

function:

```
def zip_diy(x,y):
return map(lambda a, b: (a,b), x, y)
## Example
list_1 = [1,2,3]
list_2 = [3,2,1]
list(zip_diy(list_1, list_2))
## [(1, 3), (2, 2), (3, 1)]
list(zip(list_1, list_2))
## [(1, 3), (2, 2), (3, 1)]
```

As you noticed, **map** in `zip_diy`

includes a **lambda** function that generates `(a,b)`

tuple for each element in given *iterables*, `x`

and `y`

.

**Filter** is another important tool in function programming. As you probably guessed, **filter** lets us to filter an *iterable*. In general, **filter** function is:

When the *function* is required to return a boolean type (`True/False`

) by testing each element of the *iterable*. For an example let’s select numbers greater than *22* in a list in below:

Traditionally we can use `for`

loop and `if`

condition to filter the list such that:

```
number = [88,22,11,33,2,99]
select = []
for i in number:
if i > 22:
select.append(i)
select
## [88, 33, 99]
## Or
[i for i in number if i > 22]
## [88, 33, 99]
```

Now let’s define a function to return numbers (integer, float and complex) from a list of numbers and strings: