Functions are great! You need them for everything. If you want to use code more than once, just write a function containing this code block. This makes your code easily readable, well structured, reusable and easy to share!

In the previous tutorial on working with external code, we have already seen some built-in functions (find some more here).  Also, you can be sure that if you need some standard functions, somebody, somewhere probably coded it up for you already. So just do some quick research on the internet and check out what other motivated coders made available for you open-source. But first let us investigate how we can write our own user-defined functions with this Full Stack Embedded tutorial!

Learning goals

In this tutorial you will learn all the basics on functions. This includes how to:

  • Define functions
  • Write docstrings
  • Call functions
  • Hand over arguments
  • Return 
  • Return errors

First, some theory

function-parts
Parts of a function

A function is put together as follows:

  • The function begins with the keyword def, followed by the function name, parentheses and a colon
  • Any indented code following the function header is part of the function
  • The body of the function should begin with the “docstring”
  • When the function is called, the code in the function body is executed – this is where the magic happens. For example, in this function:
    • The assignment statement assigns a value to a variable
    • The return statement returns the output value (this is optional)

This is the basic and universal function structure.

In order to make the code more readable, the so-called docstrings are used. Documenting our code is very important, as we would like to share our codes with others and at times forget what we actually coded after reading it half a year later :).

In the parentheses after the function name, different arguments can be handed over to the functions. But first things first. We now know what a basic function looks like now, so let’s try it!

Note: In the following the $ will be used for command line commands and >>> for python prompt commands.

All hands on deck

In the following we will work with some examples. We will start with a very basic example and then we will slowly add a bit of spices as we continue.

Your first function

Let’s start with something very simple, let’s try writing a function consisting of the function parts we learned above.

def greetings():
    ‘’’This function returns a greeting phrase.’’’
    phrase=”Hello! I wish you a great day!”
    return phrase

That really looks like the example above doesn’t it?! And yes, it’s really that simple. Please remember, that as soon as the indentation ends, the function ends. This is also true for any return statements – as soon as the Python interpreter reaches a return, it passes the value to the right of the return  keyword and exits the function. The same as when dealing with loops, as we learned in the previous tutorial. And please: never forget the docstring.

Call me!

We wrote our first function, so now let’s call it. Calling a function means to execute the function code. You can either do that on your command line, in your python prompt or use it in a script.

In the following we will insert the greetings function in the script first_function.py and call it on the command line. Please note, that our function does not require any input and is thus called with empty parentheses. Here’s the content of  first_function.py:

#!/usr/bin/python

# define my function
def greetings():
    ‘’’This function returns a greeting phrase.’’’
    phrase=”Hello! I wish you a great day!”
    return phrase

# Call function and print output
print(greetings())

On the command line execute the command:

$ python first_function.py
Hello! I wish you a great day!

Reading the docstring

Calling the docstrings is a great way to investigate the content of a function. In order to have a look at the docstring that we wrote in our example, we first have to import our function from the file and the call the docstring using the help function.

In the python prompt:

>>> from first_function import greetings
>>> help(greetings)
Help on function greetings in module first_function:

greetings()
      This function returns a greeting phrase.

This way you get the information needed in order to execute the functions. Using help is also very useful for looking at the documentation of a built-in function. Especially when arguments are used as input, the help method supports the understanding of the required input types and optional/required arguments. But we will get to that in the next sub-section.

Passing arguments

Previously, we learned all the tools for building, executing and calling the docstring of a function. Now let’s hand over an integer to a function that returns the squared value of the input argument. You can save the function either in the same .py file as the first function or just simply name it second_function.py.

#!/usr/bin/python
# define function
def calc_square(x):
    ‘’’This function returns the square of the input value.’’’
    square = x * x
    return square

# Call function with the integer 5 as input argument and print output
print(calc_square(5))

On the command line execute:

$ python second_function.py
25

Yay!!! We managed to write a function and call it with an input argument!

Required vs optional arguments

Some functions can be called without any input parameters (seegreetings), some with one or more required input arguments (see calc_square) and some functions can have optional named input parameters. For this purpose, a default value has to be set. Let’s make a file named third_function.py:

#!/usr/bin/python

# define function
def calc_exp(x, expo=2):
    ‘’’Return x to the power of expo. x is squared by default.’’’
    our_exp = x ** expo
    return our_exp

# Call function with 7 as required input argument and print output
print(‘With the required argument’, calc_exp(7))

# Call function with 7 as required input argument, 3 as optional
# argument and print output
print(‘With the required and optional argument’, calc_exp(7,3))

On the command line execute:

$ python third_function.py
('With the required argument', 49)          
('With the required and optional argument', 343) 

You can also find required and optional arguments in the built-in functions. In order to look at the documentation of a built-in function use the built-in help function (i.e.help(sum)). This is also how you call the docstring for one of your self-built functions. Please don’t forget to import the functions first though.

Anonymous arguments with *args

Using multiple optional arguments is quite a beauty as it is so simple. Let’s say we are packing our suitcase. The first argument is the ‘required argument’. The rest of the arguments are optional parameters in case there is enough room in the suitcase 🙂 For our example we use a list of strings as an argument list. Let’s put this into fourth_function.py:

#!/usr/bin/python
# define function
def bag(must, *maybe):
    ‘’’Help me pack my bag.’’’
    print(‘I absolutely need to pack my: ’ + must)
    for arg in maybe:
        print(‘If there is still room, I can also take my: ’ + arg)
# Call function with anonymous arguments
bag(‘passport’, ‘toothbrush’, ‘food’, ‘book’, ‘tshirt’)

On the command line execute:

$ python fourth_function.py
I absolutely need to pack my: passport
If there is still room, I can also take my: toothbrush
If there is still room, I can also take my: food
If there is still room, I can also take my: book
If there is still room, I can also take my: tshirt

Declared arguments with **kwargs

Multiple arguments can also be used for dictionaries, instead of *args with anonymous arguments, **kwargs (keyword arguments) are used. Using **kwargs, our example from above would look like this:

def suitcase(must, **kwargs):
    '''This is the function to help me pack my bag.'''
    print('I absolutely need to pack my:' + must)
    for key in kwargs:
        print('If there is still room, I can also take:' +
              key + " " + kwargs[key])


When we run this, it produces:

>>> suitcase(must='passport',
             item2='toothbrush',
             item3='food',
             item4='book',
             item5='tshirt')
I absolutely need to pack my: passport
If there is still room, I can also take: item2 toothbrush
If there is still room, I can also take: item3 food
If there is still room, I can also take: item4 book
If there is still room, I can also take: item5 tshirt

Oh no… I broke it

Errors happen and we learn from them. Let’s have a look at our previous function calc_exp. In the example, we called the function with an integer. What happens when we accidentally call calc_exp with a string input?

>>> from third_function import calc_exp
>>> calc_exp('Z'))
TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'

In case an error occurs it is a advised to go back to the code and handle it. A possibility for handling the above improper use of the function is:

#!/usr/bin/python

def calc_exp(x, expo=2):
    """ Return x to the power of expo. x is squared by default."""
    if isinstance(x, str):
        raise TypeError(
            "Whoops, your input was a string. Please use a number!")
    return x ** expo

Calling our revised calc_exp function now raises the clear error:

>>> calc_exp(‘Z’)
TypeError: Whoops, your input was a string. Please use a number!

The output now tells you exactly what your error was and how to deal with it. You can also raise an error on purpose if you want to ensure that your function behaves exactly in the way you want it to. Try to think through all the possible inputs a user could call your function with. You surely want to have a stable code. How to handle possible errors and exceptions can be found here.

Looking deeper: Arguments in functions

“Normal” arguments

Let’s take a closer look at the more complex concepts *args and **kwargs.

In function heads, any arguments specified without a default value are required. Thus, these arguments have to be passed when the function is called. For example:

# We define a function
>>> def words(required):
>>>     print ("required arg: " + required)
...
>>> # Now we call the function.
>>> words("required argument")
required arg: required argument
>>> # The argument required must be given!
>>> # Otherwise the call produces an error
>>> words()
...
TypeError: words() takes exactly 1 argument (0 given)

It’s also possible to specify optional arguments. Python knows that these arguments are optional because they have default values. Like this:

>>> # We define a function
>>> def words2(required="Nothing"):
>>>     print ("passed arg: " + required)
...
>>> # Now we call the function.
>>> words2("required argument")
passed arg: required argument
>>> # Not defining the argument required tells the function
>>> # to use the default value, "Nothing"
>>> words2()
passed argument: Nothing

If you want, you can define functions that have both required and optional arguments – that’s not a problem. However, when defining the function, the required arguments have to be listed first in the function head, followed by any optional arguments.

*args and **kwargs

*args and **kwargs, on the other hand, can be used for undefined arguments. This means any arguments that you don’t know about at the time you define the function. Normally, this isn’t required, so it’s a good idea to only use these special arguments if you have a good reason to do it. Examples are when you’re writing subclasses of library code and you think the parent classes you’re basing your code off of might be extended to accommodate more arguments.

Why are these special arguments called args and kwargs?They don’t have to be – it’s a convention. The only requirement is that args (or whatever you name it) is preceded by one asterix* – and that kwargs (or whatever you call it) is preceded by two asterix**. They stand for “args” or “arguments”, and “keyword args” or “keyword arguments”, respectively. You’ll see why in a second. The important thing to remember is that although you don’t have to name your args and kwargs that, if you do, other developers will understand what you meant and what those arguments do right away, without trying to have to decipher your code.

They work like this: Any arguments that aren’t found in the function head are bundled into the variables args or kwargs. Arguments that weren’t in the function head and aren’t named in the function call are passed into the function as a tuple named args, while named arguments that weren’t listed in the function head are passed into the function as a dictionary named kwargs, where the arguments’ names are the dictionary’s keywords with corresponding values taken from the arguments.

This is easier to understand with an example:

>>> # We define a function using *args and **kwargs
>>> def my_fun(*args, **kwargs):
>>>     print(args)
>>>     print(kwargs)
...
>>> # With no arguments, the tuple and dictionary are empty
>>> my_fun()
()
{}
>>> # Unnamed arguments go into args
>>> my_fun(1, 2, 3)
(1, 2, 3)
{}
>>> # Named arguments go into kwargs
>>> my_fun(this="that", foo=42)
()
{'this': 'that', 'foo': 42}
>>> # You can mix named and unnamed arguments
>>> my_fun("foo", "bar", name="hulk")
('foo', 'bar')
{'name': 'hulk'}

You can use these properties of args and kwargs in order to obtain and process variables, like in any other context.

You’re up!

Next please get creative and test your self-built functions! Inside the functions you can write everything that you have learned in the previous tutorials: Try using some built-in functions and loops. What would you pack in your suitcase if the weather is sunny or rainy? Can you formulate different possibilities of treating potential errors?

Further reading

I hope you enjoyed your fun with functions! If you want to read a bit more or learn a bit more, check out the pages listed below and continue doing all the Full Stack Embedded tutorials. And please remember that Google is one of your best friends while coding. A lot of people in the coding world are happy to share their experience and functions with you. So if you are looking for a special function, check online if somebody else has already done the job for you (and give them credit for it if they did). Also have a look online when encountering errors. Other people make mistakes too and for loads of the problems, the solutions are online.

Have a look at:

Advertisements