---
tags: python-course
title: lesson-04
---
# Functions and Programs
[](https://hackmd.io/VWc9UUasQXa_cbnjOcugcg)
:::info
:bulb: Useful programs are built from more basic building blocks.
Personas: Teacher is James, student is Nina.
:::
:::success
:movie_camera: VIB background fading to course title slide. James and Ninas smiling faces appear.
:::
:::warning
:notes: Upbeat intro music
:::
**Nina**: Is there a way to organise programs so that they're easier to understand and less messy?
**James**: Yeah of course! There are lots of ways to organise programs, but we should start by talking about the most fundamental one: the function. A function allows you to hide the details of some computation and then you only have to refer to it by a name you choose. This allows you to de-clutter whatever you're trying to do.
**Nina**: That sounds perfect. How do I define a function?
> [name=James] introduce the term "argument".
**James** (over animation): Let's make a simple function to see how it's done. You start by writing the keyword `def`, short for, "DEFINE. Or, Python, can you please define a function for me?". Then you type a space before choosing a good descriptive name for your function. I'm going to write a function that greets someone so let me call it "greet". Then you type a comma seperated list of variable names for your function inputs between parentheses. The inputs to your function are often called arguments. In this case there's only one input called "name". Don't forget the colon. Then on the next line you can write out the "body" of the function which _must_ be indented. The body of this function concatenates "Hello" with the name argument. For example, if name contains, "Nina" then the greeting variable will contain the string, "Hello, Nina". Finally, the result value from your function should be "returned" using the `return` keyword.
:::success
:movie_camera: Animation of a function with parts highlighted as they're described.
```python=
def greet(name):
greeting = "Hello, " + name
return greeting
```
:::
**Nina**: If I ever want to greet someone I can just run this function?
**James**: That's right! You've hidden away the details about how to greet someone.
**Nina**: How do I run it then?
**James** (over animation): That's the easy bit! Just type out the name of the function you want to use, "greet". Now who do you want to greet?
**Nina** (over animation): My cat, "Saoirse".
**James** (over animation): The string "Saoirse" is the argument to the "greet" function. Running this function gives you "Hello, Saoirse".
:::success
:movie_camera: Animation of calling a function.
```python
>>> greet("Saoirse")
"Hello, Saoirse"
```
:::
**Nina**: Why don't I use the assignment operator to put a value in the "name" variable?
**James** (over animation): Excellent question! Python does that for you behind the scenes. Although you can do it explicitly like this. They're exactly equivalent.
:::success
:movie_camera: Morph previous animation into this:
```python
greet(name="Saoirse")
```
:::
**Nina**: Can I assign the name variable before running the function?
**James**: No! The code here that _uses_ the "greet" function does not have access to the name variable. It is just like any other variable but ONLY in the context of the "greet" function body. It is not accessible to the code that uses "greet".
**Nina**: Wait, what's the context of the function body?
**James**: Notice that the "body" of the function is "indented". All of the indented lines make up the context of your function when Python is running your code. You can think of the function as an isolated program that can define it's own variables. These variables are only accessible to other parts of the body and nowhere else.
**Nina**: That seems limiting!
**James** (over animation): Yes it is limiting. But that's a good thing, I promise. Because it is isolated, you don't need to think about how all of the other parts are functioning, you only need to think about how your little isolated function is working. This will become important later, for now you only need to know that a function body is isolated from everything outside it. And you make a line of code part of the function body by "indenting" it.
:::success
:movie_camera: Animation zooms out to other (blurry) functions in the program to show that you can focus on one function at a time.
:::
**Nina**: Alright, the greeting for `"Saoirse"` should be `"Hello, Saoirse"`, how do I get that out of the function if it's isolated?
> [name=James] Explain the difference between print() and return.
**James**: That is why we have to use the `return` keyword. It tells Python to output whatever value we type after "return". You can use the assignment operator to capture the returned output into a variable if you like.
**Nina**: Why does "greet" not just `print` "Hello, Saoirse" instead of returning it?
**James**: Printing and returning are very different. Although printing is very useful for understanding what your program is doing, printing does not give you a value you can work with later. Returning extracts a value that you can print, save to a file, plot on a graph, or do anything else that you can do with values. Generally speaking your functions should return a value, that's more useful than printing.
**Nina**: If I have a computation that requires multiple inputs. For example, if I need to compute the alignment of 2 sequences. How can I give both sequences to my function?
**James** (over animation): Yeah! The greet function only accepts a single value into the "name" variable. But, when you define your function, you can specify any number of input variables seperated by commas.
:::success
:movie_camera: Animation highlighting input variables, adding N more.
```python
def align(seq1, seq2, ..., threshold, matrix,...):
...
```
:::
**James** (to the camera): Can you experiment with defining your own functions now? What happens if you forget to use the `return` keyword?
:::warning
:notes: Waiting music
:::
**James**: Because programmers are human, we often make mistakes, even the best programmers make mistakes. Let's look at some common mistakes programmers can make when defining functions so you're familiar with the symptoms. To start with, what happens if you try to run your function without putting parentheses after the name?
:::success
:movie_camera: Demo evaluating the value of a function and correct by using parentheses (don't run with parens yet, that will lead to the next error).
:::
**Nina**: Python tells me that `greet` is a function with some numbers I don't understand.
**James**: Yes it is a function, but you didn't run it. You just asked for the value in a variable. You need to use parentheses to run the function. What happens if you try treat something that isn't a function as if it is a function?
:::success
:movie_camera: Demo assigning calling something not a callable.
```python
val = 0
val()
```
:::
**Nina**: Now I get a `TypeError` that says "int" is not callable.
**James**: Programmers use the word "call" interchangeably with "run". And sometimes "execute" as well. So Python is telling you that an integer isn't a function you can run. Now, what happens if run your "greet" function but you forget to provide any input?
:::success
:movie_camera: Demo evaluating greet() without providing the correct number of inputs.
:::
**Nina**: Python helpfully tells me that I'm missing a required argument. I wonder what happens if I forget to return anything?
:::success
:movie_camera: Demo writing the function without a return.
:::
**Nina**: Nothing seems to happen?
**James**: You're telling Python that your function has no outputs so you can't get anything out of it. I think you've seen the most common mistakes now. These are the basics of using and building your own functions.
**Nina** A function is an isolated part of your program that hides the details of a computation so you can focus on the important part of the problem you're trying to solve.
**James**: Larger problems can often be broken down into simpler parts. Functions allow you to experiment with solutions to these smaller parts of your problem in isolation. This is a superpower, experiment with methods to solve your problem, see what the results are, then modify your function.
**Nina**: This concludes this lesson and our dive into the fundamentals of computation. To summarise, values and functions are the building blocks and glue you will use to solve problems in any programming language, not just Python. Everything else is detail. Of course, you will need to be familiar with these details in order to wield Python effectively.
**James**: In the remainder of this course you will build on the foundation of values, variables, and functions. Well done getting so far already!
**James and Nina**: Good luck and see you next time.
:::success
:movie_camera: Fade to VIB logo slide.
:::
:::warning
:notes: Upbeat outro music
:::