# Session 3 : Python basics recap, loops, functions Outline of this session: * 5min Check-in & starting the participation thread * 5min [](grading.md) * 15min Recap of last session * 15min Loops * 30min Functions * 20min Open experimentation There are three recordings in which I run through the following code snippets: * [Loops](https://base.uni-ak.ac.at/cloud/index.php/s/2MyasXnHqQYqRaj) (~26min, 78MB) * [Functions](https://base.uni-ak.ac.at/cloud/index.php/s/Tp8w8iSsjWBE9gi) (~34min, 107MB) * [Recursion](https://base.uni-ak.ac.at/cloud/index.php/s/xgsLf5xigPHwYGa) (~24min, 79MB) ## Loops ```python # In the last session we ended with for-loops that could loop # through a list or a function. But what if we do not want to # loop over some thing in particular, but just want to loop, # maybe with a specific stop condition of our own. # Well, let's do a simple while loop # and we will use this number as a loop condition number = 1 # no execute the loop as long as the number is smaller than 100 while number < 100: print(f'counting from {number} to {number+1}') # and maybe doing some more serious stuff here # but don't forget to update the loop condition, unless you want too loop forever number += 1 # Thanks to Al Sweigart for the following one name = '' while name != 'your name': print('Please type your name.') name = input() print('Thank you!') # now we add some more loop control structures with break and continue boredom_threshold = 42 number = 0 while number < 100: # increase the loop counter number += 1 # we only want to deal with even numbers, so we just skip odd ones if number % 2 != 0: continue # and in case we get past our boredom threshold, we just end the loop if number > boredom_threshold: break print(f'we have reached {number}') # and maybe do some more important stuff here as well ``` As a file: [](snippets/loops.py) ## Functions ```python ''' Functions ========= ... are blocks of reusable code, that can be run by invoking/calling the function wherever we want to use that code. Functions can have zero or more arguments, through which we can parameterise the function to not always do exactly the same thing. Functions can also return some value, that we can use when the function code has finished to run. But let's start with some examples:''' # we already used functions, e.g. the print function print() # this prints and empty line print() # again, does exactly the same thing print('hey there!') # now we use one argument (a string), so the function prints something else print('again, but with some other argument') # now print can take many arguments print('it will print all those', 3, 'arguments, separated by a space') # print even allows for some keyword arguments. check it out: https://devdocs.io/python~3.8/library/functions#print print('a', 'set', 'of', 'random', 'data', 23, 43, sep=';', end=';# i know, csv does not do comments, but we add this at the end of the line anyways\n') # or here a function we already used that returns something the_return_value = input('Hey, gimme something: ') ''' Defining our own functions ========================== We are not limited to using the functions that are already there. We can define our own functions. How awesome is that? This way we could rewrite the whole language basically. But let's start with some simple examples. ''' # a function that just prints some lines of code def print_greeting(): print('Hello user!') print('What a lovely day.') print('Have fun hacking around.') # now every time we want to print those three lines we don't have to write # them all along but just do: print_greeting() print_greeting() # see, just does the same thing again # let's overwrite the function and make it a bit more versatile # by introducing an argument def print_greeting(name): print('Hello', name, end='!\n') print('What a lovely day.') print('Have fun hacking around.') # now we can use the same function for different users print_greeting('Ada') print_greeting('Grace') print_greeting('Hedy') # let's add some more arguments with defaults def print_greeting(name, daytime='day', activity='hacking around'): print('Hello', name, end='!\n') print(f'What a lovely {daytime}.') print(f'Have fun {activity}.') # now we can use the same function for more personalised greetings print_greeting('Ada') print_greeting('Grace', 'morning') print_greeting('Hedy', 'evening', 'frequency hopping') print_greeting('Margaret', activity='launching space ships with code') # now some other functions that actually return something def my_own_much_better_addition(num1, num2): result = num1 + num2 # actually not really better, just an addition return result # we now can call the function and it will provide some result my_calc = my_own_much_better_addition(23, 42) print(my_calc) # something more interesting that returns a more interesting data structure too def get_user_details(): name = input('Hey user, what\'s your name? ') activity = input('And what is your favourite activity? ') return { "name": name, "activity": activity, } # which we now can use every time a user logs on, to later print the greeting user_details = get_user_details() print_greeting(user_details['name'], activity=user_details['activity']) # And now for an important but not that often used concept: '''***************************** *** *** *** R E C U R S I O N *** *** *** *****************************''' # do you know the factorials? # mathematically written: n! = n * (n-1)! # more background: https://en.wikipedia.org/wiki/Factorial # here's a list of the first few factorials there are (for 0 and 1 it is defined axiomatically) factorials = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880] # so how could we get more of them? for _n in range(100): factorials.append(factorials[-1] * len(factorials)) print(f'wow, now we have the first {len(factorials)} in a list:', factorials) # this is how a function could look like that uses such a list, to return n! def factorial_list(n): # for 0 and 1 the output is just defined as 1 if n in [0, 1]: return 1 # if n is bigger than 1, we'll create our list f_list = [1, 1] for i in range(2, n+1): f_list.append(f_list[-1]*i) # now we can return the last item of the list which is n! return f_list[-1] # but there is a much smoother way to do that, without any list # just by calling the same function within the function itself (:= as a recursion) def factorial(n): if n in [0, 1]: return 1 return n * factorial(n-1) # we can check now, whether those two functions really do the same thing and # produce the correct factorials for numbers from 0 to 10 for i in range(10): print(f'factorial({i}) : {factorial(i)}') print(f'factorial_list({i}) : {factorial_list(i)}') # Ok, so this was an example of what recursion is an can do. # You might not need it very soon or at all. But keep in mind # that there are some problems which are better solvable with # recursion. E.g. a dict, that contains a `data` dict, wich # again can contain a `data` dict and so on. And you don't know # how deep this nesting goes. This is one case where recursion # could come in as quite a handy feature. ''' Well, this was a lot. Still, there is a lot more. But now you know all the basics you need to write your own functions. At some point you might want to split up your functions into different files, and in your main script import those functions from those "modules". But let's leave it for now. If you want to know more, take a look e.g. at those: * https://www.w3schools.com/python/python_functions.asp * https://www.w3schools.com/python/python_modules.asp Or you want to go full functional? Then take this: * https://www.w3schools.com/python/python_lambda.asp But I'd recommend not to overdo it. You don't need to be fully functional to be an esteemed member of our coding club. ;) ''' ``` As a file: [](snippets/functions.py)