# Functions#

We have used already used functions (e.g., `imread(some_path)`

) in past lessons. Functions have a name and parameters. Some of them return a result, others don’t. We typically call them like this:

```
result = function_name(parameters)
```

See also

Let’s take a look at some functions, for example `print(text)`

and `pow(x, y)`

. The print function takes a parameter (or multiple parameters) and returns nothing:

```
result = print('Hello world')
```

```
result
```

The pow function has two parameters and returns a result:

```
result = pow(2, 3)
```

```
result
```

## Custom functions#

You can **DEF**ine your own functions using the `def`

statement. After the def statement, you should specify your functions’ name and in brackets its parameters. Afterwards follows a colon `:`

and all following lines of code which are indented are part (*“inside”*) of this function. A final `return`

statement sends the result back to from where the function was called.

```
def sum_numbers(a, b):
result = a + b
return result
```

You can then call your function as often as you like

```
sum_numbers(3, 4)
```

```
sum_numbers(5, 6)
```

Sometimes, you want to save the result of your function in a variable.

```
c = sum_numbers(4, 5)
print(c)
```

### Simplify code using functions#

Assume you have a complicated algorithm which can tell you if a number if odd or even. Let’s put this algorithm in a function and call it later on. For our algorithm, we will use the modulo operator %.

```
def print_odd_or_even(number):
if number % 2 == 0:
print(number, "is even")
else:
print(number, "is odd")
```

```
print_odd_or_even(3)
```

```
print_odd_or_even(4)
```

```
print_odd_or_even(10)
```

Thus, instead of writing the same `if-else`

block again and again, we can just call our custom `print_odd_or_even`

function.

### Documenting functions#

You can document what a function does in its so called doc string. The doc string follows right after the functions header and looks like this:

```
def square(number):
'''
Squares a number by multiplying it with itself and returns its result.
'''
return number * number
```

You can then later read the documentation of the function like this:

```
print(square.__doc__)
```

Also try this if you want to have the docstring shown side-by-side in your notebook:

```
square?
```

By the way, you can do this with any function:

```
import math
print(math.sqrt.__doc__)
```

```
print(math.exp.__doc__)
```

## Methods#

Methods, as opposed to function are functions that can be executed directly from a variable. They are defined in the same way as functions, but they are called in a different way.

Normal function:

`function_name(arguments)`

Method:

`variable_name.method_name(optional_arguments)`

Every type of variable has its own methods. For example, strings have methods to convert them to uppercase or lowercase, to replace a substring, to split them, etc.

```
name = 'Johannes'
name.lower()
```

```
filename = 'my_image.tif'
filename.endswith('.tif')
```

Numpy arrays also have a few handy methods you can directly use on them. For example, you can use the `mean()`

, `.std()`

or `.sum()`

methods to calculate the mean, standard deviation and sum of the elements in an array, respectively.

```
import numpy as np
```

```
# create some random data
array = np.random.randint(low=0, high=3, size=[3,3])
array
```

```
print(f'Mean: {array.mean()}')
print(f'Standard deviation: {array.std()}')
print(f'Sum of all elements: {array.sum()}')
```

In some cases, these methods take optional arguments customize the call. For install, the `mean`

, `std`

and `sum`

functions take an optional `axis`

argument that specifies which axis to perform the operation on.

```
print(f'Sum of all elements along first axis: {array.sum(axis=0)}')
print(f'Sum of all elements along first axis: {array.sum(axis=1)}')
```

# Exercises#

## Exercise 1#

Write a function that takes two parameters: `number_of_points_achieved`

and `number_of_total_points_in_exam`

and returns a grade from 1 to 5. Students with > 95% of the points get grade 1, above 80% they get grade 2, above 60% grade 3 and above 50% grade 4. Students with less than 50% get grade 5 and have to repeat the exam. Then, call the function for three students who had 15, 25 and 29 points in an exam with 30 total points.

```
grade_student_exams(20,30, pass_only=True)
```

## Exercise 2#

write a docstring for your function that describes what it does, the input parameters it expects and the output it returns.

Explore how the jupyter autocompletion and inspecting it with a `?`

helps you when you use the function.

## Exercise 3#

add an optional parameter `pass_fail=True`

to add the possibility to evaluate an exam where students with more than 50% pass the exam.

## Exercise 4#

split the complicated function from Exercise 3 into two simpler functions