Introduction to Python Functions
Published: 2021-08-03 06:28:16

#What is a function?

A function is a set of instructions/ block of code that is put together to achieve a specific outcome or perform specific tasks.
Functions enable us avoid having repetitive blocks of code in our program making it easy to read and maintain.

Functions in python are either **built-in** or **user defined**.

##Built-in functions.
These are functions that come with python installation. For example the `print()` function that is used to print to the console.
Other types of built-in functions include `float()` which returns a floating type number, `input()` which allows user input, `int()` which returns an integer, etc.

##User defined functions.
These are functions that a developer creates in order to perform a given task.

Functions are defined using the `def` keyword followed by the function name and parenthesis then a full colon.
```
def my_function(parameters):
    """Docstring"""
    statement
    return
my_function()
```

The function body consists of an optional **docstring** that is written inside triple quotation marks. It's optional but advisable as good practice to include a docstring at the start of your function as way to describe what the function is supposed to do.

The statement refers to the code in  the function. It could be an if statement, a for loop, a print statement or any other code that maybe added to the function. This must be indented.

The `return` statement is a keyword that exits a function optionally passing back an expression to the caller.
The return statement can be written without any arguments and in that case its the same as return None so it will just exit the function.

However, there can be arguments added after the return statement. The return statement can consist of a variable, or expression which is returned at the end of the function execution.

Finally the function call which is done by writing the name of the function followed by parenthesis. The parenthesis is filled with arguments that are passed when calling the function. Sometimes they can be left empty. The function call is **de-indented** and at the same margin with the def keyword.

The parenthesis in the function definition can either be left empty or filled with parameters.

##Function arguments.
An argument is a value that is sent to the function when it is called. It's important to note that by default a function should be called with the correct number of arguments, meaning that if your function expects two arguments, it must called with two arguments not more not less lest it throws an error.

There are different types of arguments in python functions.

###Default arguments.
This is an argument  that assumes a default value if a value is not passed in the function call for that argument.
```
def car_brand(brand="Toyota"):
    print("I drive a " + brand)

car_brand("Benz")
car_brand("Jeep")
car_brand("Volvo")
car_brand()
```
The above code will produce the following when run.
```
I drive a Benz
I drive a Jeep
I drive a Volvo
I drive a Toyota
```
The last function call was provided no argument so when it was called, the default argument that was supplied in the function definition was passed.

###Keyword arguments.
When using keyword arguments, you provide names to the parameters as you pass them through the function definition so during the function call, the caller identifies the arguments by the parameter names.
This allows you to place arguments out of order since the python interpreter is able to use the keywords provided to match the values with the parameters.
```
def my_friends(friend1, friend2, friend3):
    print("My best friend is " + friend1)

my_friends(friend3 = "Mark", friend1 = "James", friend2 = "Sophie")
```
This function will return:
```
My best friend is James
```
The order in which you call the arguments doesn't matter.

###Arbitrary keyword arguments
If you don't know how many keyword arguments will be provided into your function, add two asterisks `**` before the parameter name in the function definition. 
Usually the keyword `**kwargs` is used to represent keyword arguments.
The double asterisks allow us to pass any number of keyword arguments.
```
def favorite_place(**kwargs):
    print("My favorite city is " + kwargs["city"])


favorite_place(country="England", city="London")
```
This code will produce the output below:
```
My favorite city is London
```

###Arbitrary arguments (*args)
If you don't know the number of arguments that will be passed into you function, add an asterisk (*) before the parameter name in the function definition. The function will receive a tuple of arguments and access them accordingly.

Using the *, the variable that we associate with the * becomes an iterable meaning you can do things like iterate over it.
```
def friends(*args):
    for friend in args:
        print(friend)

friends("Marcus", "James", "John", "Oliver")
```
The code above iterates through the args and prints out each friend passed in the friends function. You can pass as many arguments in friends as you want and they will all be printed out.

###Anonymous functions.
Anonymous functions aren't declared using the def key word. Instead, the key word **Lambda** is used.

A Lambda function can take any number of arguments but return just one value in form of an expression. They are restricted to a single expression.

`lambda arguments: expression`

`lambda x,y: x+y`

Here x,y are the arguments and x+y is the expression.

An advantage of using Lambda functions is that you can write a function in one line of code making it concise.
```
add = lambda x, y: x + y
print(add(5 , 6))
```
The above lambda function adds two numbers together.

When the same function is written with a function definition, It is longer 
```
def add(x, y):
    return x + y

print(add(5, 6))
```
yet both these functions return the same result.

I hope this brief introduction makes functions in python a bit easier for you to understand. Cheers.