<jupyter_start><jupyter_text>FunctionsFunctions in Python work straight-forward: They (optionally) require a set of inputs, perform some internal operations, and return a result. Now, we could either go on talking about the basic syntax of function declaration, how the whole story works, etc... OR we could simply take a look at the following image that puts it all in a graphical, and hence, easy-to-understand context (all the credit is due to LearnICT.it):            Source: http://hcc-cs.weebly.com/functions.html   Okay, so just for the record, here's the syntax of function definitions in Python:> `def` **function_name** `() :` > &ensp;&ensp;&ensp;indentedFunctionBodySo, what's the purpose of functions anyway? Well... suppose we wanted to write some Python code that reproduces the lines of the famous "Happy Birthday" song (taken from here). In order to achieve this and assuming our birthday child's name is Chris, we could simply use some `print` calls:<jupyter_code>print("Happy birthday to you.")
print("Happy birthday to you.")
print("Happy birthday, dear Chris.")
print("Happy birthday to you.")<jupyter_output>Happy birthday to you.
Happy birthday to you.
Happy birthday, dear Chris.
Happy birthday to you.<jupyter_text>But what if we wanted to reuse this code to congratulate someone else, e.g. named Thomas? There's basically two (fundamentally different) approaches here: We could either copy and paste the above code, replacing the name of the birthday child:<jupyter_code>print("Happy birthday to you.")
print("Happy birthday to you.")
print("Happy birthday, dear Thomas.")
print("Happy birthday to you.")<jupyter_output>Happy birthday to you.
Happy birthday to you.
Happy birthday, dear Thomas.
Happy birthday to you.<jupyter_text>Or &ndash; and here's where the high art of programming actually begins &ndash; write a function that takes a certain input variable (i.e. the name), performs some processing steps (i.e. put the single lines together), and returns the result (i.e. the complete song).<jupyter_code>def birthdaySong(name):
    print("Happy birthday to you.")
    print("Happy birthday to you.")
    print("Happy birthday, dear ", name, ".", sep = "")
    print("Happy birthday to you.")
    
birthdaySong(name = "Thomas")<jupyter_output>Happy birthday to you.
Happy birthday to you.
Happy birthday, dear Thomas.
Happy birthday to you.<jupyter_text>Using our newly gained knowledge about E02-1: Loops and E02-2: Conditionals from before, we could take this even a step further and restructure the function's body using a `for` loop together with embedded `if-else` statements:<jupyter_code>def birthdaySong(name = "Chris"):
    for i in range(4):
        if (i != 2):
            print("Happy birthday to you.")
        else:
            print("Happy birthday, dear ", name, ".", sep = "")
            
birthdaySong()<jupyter_output>Happy birthday to you.
Happy birthday to you.
Happy birthday, dear Chris.
Happy birthday to you.<jupyter_text>Please note that in the latter version, we also set a default value for `name` in order to save some typing work on Chris's birthday. In the end, it is totally up to you which of the two versions you prefer, i.e. four `print` statements in a row or rather the nested `for`/`if-else` solution.   The `return` statementSo far, you have only encountered selfmade functions that `print` some text to the console. However, the majority of functions you'll be writing in the future need to perform actual calculations based on a set of input variables and then return an output object. Therefore, in addition to the things we have just learned, bear in mind to insert a `return` statement whenever you are actually trying to return an object. For example,<jupyter_code>def f1():
    return()

f1()<jupyter_output><empty_output><jupyter_text>returns an empty `tuple`, whereas<jupyter_code>def f2():
    return(5)

f2()<jupyter_output><empty_output><jupyter_text>returns an `int` object. Accordingly, a custom `sum` function that takes a sequence of numbers as input could roughly look as follows:<jupyter_code>def sumPy(x):
    out = 0.0
    
    for i in x:
        out += i
        
    return(out)

sumPy(range(0, 6))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.08714184229220932, 'fraction_numerical': 0.004025574236324887, 'mean_word_length': 4.436293436293436, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '391699', 'license': 'MIT', 'n_tokens_mistral': 1198, 'n_tokens_neox': 1140, 'n_words': 551, 'path': 'docs/mpg-if_error_continue/examples/e-02-3_functions.ipynb', 'repo_name': 'marburg-open-courseware/gmoc', 'size': '4223'}