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:

```
def name(par1, par2, par3, ...):
"Documentation."
bodyreturn result
```

For example:

```
def mult(a, b):
"Two numbers multiplication."
= a * b
m return m
12, 13)
mult(## 156
```

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.
"""
= 0
result while b > 0:
+= a
result -= 1
b return result
12, 13)
mult_itr(## 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)
12, 13)
mult_rec(## 156
```

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

```
12
12 + 12
12 + 12 + 12
...12 + 12 + ... + 12 (13 times)
```

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)
6)
fact(## 720
def fact_itr(n):
"""
Compute n factorial by iteration.
Note that n! is equal to n(n-1)(n-2)...1.
"""
= 1
result while n > 1:
*= n
result -= 1
n return result
6)
fact_itr(## 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)
6)
fact_rec(## 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.
"""
= 5**0.5
phi if n < 2:
return n
else:
return ((1+phi)**n - (1-phi)**n)/(2**n * phi)
for x in range(12)]
[fib(x) ## [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 = 0, 1
a, b while len(series) < n:
series.append(a)= b, a + b
a, b return a
for x in range(12)]
[fib_itr(x) ## [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)
for x in range(12)]
[fib_rec(x) ## [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*):

```
5)
fib_rec(|________
_______| |
4) fib_rec(3)
fib_rec(|___ ___|___
___| | | |
3) fib(2) fib(2) 1
fib(|__ __|__ __|__
__| | | | | |
2) 1 1 0 1 0
fib(|__
__| |
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:

`= lambda par1, par2, par3, ...: body name `

For example:

```
= lambda x: x**3
cube
2)
cube(## 8
```

Which is same as:

```
def cube(x):
return x**3
2)
cube(## 8
```

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

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

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

```
= lambda f, x, z: eval(f.replace(str(x), str(z)))
re
## Example
= '2*x + 5'
f 'x',2)
re(f,## 9
```

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)
= lambda x: x**3
f 2)
deriv2nd(f, ## 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:

```
import sympy
= sympy.symbols('x')
x = x**3
f = f.diff(x,2)
ff
ff## 6*x
2})
ff.subs({x:## 12
```

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

`map(function, iterable, ...)`

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:

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

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

```
= [(1,3,4,5),(3,4,5,6),(7,6,5,5),(8,6,9,1)]
sale = []
seasonal for i in sale:
sum(i))
seasonal.append(
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:

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

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

```
= [2.0678,3.9870,4.7869,5.3459]
flt list(map(round, flt, [2]*len(flt)))
## [2.07, 3.99, 4.79, 5.35]
```

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
= [1,2,3]
list_1 = [3,2,1]
list_2 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:

`filter(function, iterable)`

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:

```
= [88,22,11,33,2,99]
number list(filter(lambda x: x > 22, number))
## [88, 33, 99]
```

Traditionally we can use `for`

loop and `if`

condition to filter the list such that:

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

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

```
def return_num(lis):
return filter(lambda x: isinstance(x, (int,float,complex)), lis)
## Example
= [2.05, 3, 'aaa', 4.23, 'bbb', 7j]
test list(return_num(test))
## [2.05, 3, 4.23, 7j]
```