# Functions

Hey there, welcome back to the Python basics tutorial! So far you've seen a lot of *functions* be used throughout the series, although you may not have noticed them. Some inbuilt functions in Python are `print()`, `input()`, `max()` and `min()`, all of which you've already seen being used. A function is like a small piece of code that is *only* executed when you call the function. You can call the function as many times as you want.

## Basics

The structure or *syntax* of a function as we'll call it while programming is like this:

```python
function_name(data, more_data)
```

We put the function's name, and right next to it, **without spaces**, we pass data **separated by commas** and **enclosed with parentheses**.

We can, for example pass more data to `print` than just a single string:

```python
print('Hello', 'World', 'Davy', 'Jones')
# Prints "Hello World Davy Jones"
```

The data we're passing are actually called arguments. Now, how do you define your own functions?

```python
def say():
    print('Hello, World!')
```

We use `def` to say, "Oi, I'm defining a FUNCTION here!", followed by the function's name, and since we do not need any data to be given, an empty pair of parentheses, followed by a colon `:`. Then we indent the next lines to show that they're part of the function definition.

Run the code. What do you see? Nothing! As I said, the code is *only* executed if you call the function. How do we call it then?

```python
def say():
    print('Hello, World')
say()
```

Now you should see "Hello World" being printed.

Alright, you have to admit, that's not really a useful function. Let's accept a value.

```python
def say(name):
    print('Hello', name)

say('Jack Sparrow')
```

So, we put a variable called `name` inside the parentheses when defining the function. After that, we use it just like a regular variable. You probably noticed that we never assign anything to the variable. So, we pass the string "Jack Sparrow" to the function, which is automatically assigned to the variable `name`, and we can print it out. The variable we put inside the parentheses while defining the function is called a **parameter** and the value or data we pass to the function via those parameters is called an **argument**.

Let's try to add more arguments, shall we?

```python
def talk(name, age):
    reply = 'Hey there, ' + name + '! You\'re ' + str(age) +' years old.'
    print(reply)
    
talk('Jack Sparrow', 21)
```

Simple, right? Let's make an adder:

```python
def add(a, b):
    print(a + b)

add(9, 10)
```

Awesome.

## Returning from functions

So far we've been using functions to print values directly. What if we wanted to save the value to do something later? We would make the function "return" a value.

```python
def add(a, b):
    return a + b
```

Here, we use the `return` **keyword** to return a value. But where is it? You have to receive the value too, usually with a variable:

```python
def add(a, b):
    return a + b

answer = add(1, 3)
print(answer)
```

Nice. We have a working and actually useful function now.

{% hint style="info" %}
A `return` is the end of a function. You cannot use any more code after a return. You can use an empty return to exit from a function before it ends.
{% endhint %}

## Optional arguments

You can use optional (aka keyword or named) arguments too. You just fill in a default value, if that argument is not given, the default value is used.

```python
def food(fish, meat='Chicken'):
    print(fish, meat)

food('Tuna', 'Beef') # Prints Tuna and Beef
food('Salmon') # Prints Salmon and Chicken

def food(fish, meat):
    print(fish, meat)

food('Tuna')
# TypeError: food() missing 1 required positional argument: 'meat'
```

As you can see, if we make `meat` a **positional** or required argument, we HAVE to pass a value for it.

## Recursion

If you call a function within the function it's called recursion. For example:

```python
def factorial(num):
    if num == 0:
        return # Exit if num is 0
    else:
        return num * factorial(num-1)
```

Hopefully if you paid attention during math class, you know what's going on. In the last line, we call the multiply `num` by the output of `factorial(num-1)` which multiplies `num-1` with the output of `factorial(num-1-1)` and so on...

That's recursion! If we didn't specify the exit condition, the function would go on and on until we reach the recursion limit. Recursion is generally not recommended, and you should use loops. But again, there are always exceptions.

That's it for this lesson. You'll see a lot more in the upcoming chapters, such as how to receive a potentially infinite number of arguments.

I'll leave you with that cliffhanger there :)
