# Functions in Python This is a note for IBDP explaining the concept of functions :::info :clock1030: We have already talked about functions. When we did the [functions with the morse code](/2OLbqEc6SnuhkR-RcrGRDA) ::: Functions are blocks of code that we can call whenever we want and they will be executed. That's what they have in common. So for execute a function we need 2 things. The DEFINITION of the function and then the CALL of the function Let's see with an example ```python!= def veryCoolFunction(): print("owo") veryCoolFunction() ``` In line 1 we have the _signature_ of the function with the keyword `def`, the name of the function, the parenthesis and the colon (`:`). They are mandatory and if you don't write them the interpreter is going to say `how about no` In line 2 we have the block of code (indented) that is going to execute. This is called also the _implementation_. In line 4 we have the _call_ of the function So what's going to happen is that the interpreter is going to read the function, save it in memory and then, when we arrive to line 4 it's going to go back to the function that it has in memory and execute it. ### Exercise This is a small exercise to be aware of identation. How many times is woof going to be printed? ```python!= def barkingDog(): print("woof") print("woof") print("woof") barkingDog() barkingDog() ``` Solution: :::spoiler 5 ![image](https://hackmd.io/_uploads/H1oc6eRAee.png) There are 2 calls to the function but line number 3 is outside of the function so is going to be executed only once. ::: ## Return statement In math we're used that functions they change stuff. $f(x)$ is usually different from $x$ and we usually want to know $f(x)$. In programming is very common that a function returns something. This can be any value. We use the `return` statement and then the value that we want to return. The 'return' statement ENDS the function, so any other instructions in the function are ignored. This can be handled by the code that is calling the function. ```python!= def myBelovedBooleanGenerator(): return True def myBelovedNumberGenerator(): return 17 def myStringGenerator(): return "woofie woof" x = myBelovedNumberGenerator() + myBelovedNumberGenerator() print(x) #34 print("The styilish dog says " + myStringGenerator()) #The styilish dog says woofie woof print(myBelovedBooleanGenerator()) #True ``` We are going to usually want to do something more that returning a specific value (*except for **accessors** that we're going to cover in OOP, Object Oriented Programming*) but I want to make this exercise first. :::info **Output** and **return** are 2 different concepts. One is going to output something to the user (or the console), the other is going to return a value to the line of code that was calling it. ::: ## Parameters One of the key elements in the calling and the definition of a function are the parenthesis `()`. Inside these parenthesis we may have parameters. This is like the $x$ that we write in $f(x)$. For example we may do a function that is called "square" that if you give it a number is going to return the square of that number. ```python!= def squared(input): return input*input #the implementation of the function ends here x = 3 print(x) #3 x = squared(x) #x is going to be the output of squared of its value print(x) #9 ``` We may have more than one parameter. Another even more trivial example would be addition of 2 numbers ```python!= def addition(x, y): return x+y #implementation of the function ends here potato = 5 tomato = 10 print(addition(potato, tomato)) print(tomato+potato) ``` ## Where are the functions defined in python ```python!= potato = 5 tomato = 10 print(tomato+potato) print(addition(potato, tomato)) def addition(x, y): return x+y ``` This gives us an error because addition wasn't defined before we call it. ![image](https://hackmd.io/_uploads/rkjEEGAAxg.png) ### Local variables The name of the parameters are going to make sense _only_ inside the implementation of the function. This what is called _local_ variables. There are also local variables in the _scope_ of other blocks of of code but this is one of the main ones. ```python!= def addition(x, y): return x+y #implementation of the function ends here print(x) ``` This gives us an error in line 5 and says that x is not defined. But this will work: ```python!= def addition(x, y): print(x) return x+y #implementation of the function ends here #print(x) print(addition(3,4)) ``` What will be the output of this program? :::spoiler 3 and then 7 Another exercise: ```python!= def addition(x, y): print(x) return x+y #implementation of the function ends here #print(x) print(addition(5,4)) ``` output will be 5, 9 ::: :::info We don't need to write a parenthesis in the line `return x+y` because it works like an _assignation_ statement. So it's going to operate whatever complex operation that we may have in there and then return it. Like `return a*2+b^c-(b/4)`. (in this example we need to have access to variables called a, b and c) In exams you can write it in one line(This is called the oneliner solution) or do more "step by step" (this is called "boiler plate" if done in excess) ::: ## Typing problems Python is a programming language that is loosely typed. What do we mean by that is that we don't need to stat the types of the variables when we declare them or in parameters. But sometimes we may want to do it! Imagine that we sent a string to a function that does a square (the one that we have before): ```python!= def squared(input): return input*input #the implementation of the function ends here x = "trhee" print(squared(x)) ``` This give us an error: ![image](https://hackmd.io/_uploads/BJtJiW0Agl.png) To understand the traceback, I'm going to use another version of the code with more stuff so we can interpret it together ```python!= def squared(input: int): print("we're in the function Squared") return input*input #the implementation of the function ends here x = "trhee" print(x) #three x = squared(x) #x is going to be the output of squared of its value print(x) #not executed ``` ![image](https://hackmd.io/_uploads/Hk2Gsb00el.png) This happens because typing is not __enforced__ by the interpeter. You can find more information about it here: https://docs.python.org/3/library/typing.html So be aware of this problems that you may find! ## Exercise explaining return statement These exercises are going to be similar to the one in flow control about age Construct a function that given a parameter age called "myFunction" is going to the return the following: In the case that is below 3 the program will return “Toddler”. If the age is between 3 (included) and 12 (included), the program will return “Child”. If the age is between 13 and 19 (both included), the program will output “Teenager”. In other cases, the program will return "Adult" Step by step. First we need to read the name of the function (myFunction) and if it has any parameters (age), then write the signature of the function like this: ```python!= def myFunction(age): ``` Then we write the if clauses. ```python!= def myFunction(age): if age < 3: return "Toddler" if age < 12: return "Child" if age < 20: return "Teenager" return "Adult" ``` :::warning **Why is not goin go return Toddler Child Teenager Adult if age is 2?** Because the `return` statement is going to finish the function altogether, so the next lines are not goin go be executed. ![image](https://hackmd.io/_uploads/SkkzeQARlx.png) _Return statement ending the function_ ::: Can we write this with elif clauses? Yes, we can. ```python!= def myFunction(age): if age < 3: return "Toddler" elif age < 12: return "Child" elif age < 20: return "Teenager" return "Adult" ``` ## Pass In python (this is different from other programming languages) if you want to put an empty function (_may_ happen while you don't implement it yet) you need to write a `pass` keyword. More about it here: https://docs.python.org/3/reference/simple_stmts.html#the-pass-statement ## Scope local variables and global variables In python if we want to use a variable outside of the local scope we need to state it declaring it again and saying "global" https://www.w3schools.com/python/python_variables_global.asp :::info In other programming languages, like C++ you can access already to global variables. We did that when using `dotDuration` in the morse exercise. ::: ### Exercise of scoping ```python!= number = 0 def veryCoolFunction(): global number number = number + 3 number = number + 2 veryCoolFunction() veryCoolFunction() print(number) #8 ``` What will be the output of this program? ```python!= number = 1 def veryCoolFunction(): global number number = number + 3 number = number + 2 veryCoolFunction() print(number) number += 1 # number = number +1 veryCoolFunction() veryCoolFunction() print(number) ``` ## First batch of exercises :::success These exercises require to know flow control, explained here: [Flow control in python](/zX6YpspsTnCvqmZC0vTzRg) but they don't need to know either lists or collections nor iterations in python. ::: ### Is it day time? Construct in python a method (function) that called isDayTime that is going to return true in case that a given hour is between 8 and 18 and is going to return false otherwise. :::spoiler ```python!= def isDayTime(hour): if hour>=8 and hour<=18: return True return False ``` Another solution ```python!= def isDayTime(hour): if hour>=8 and hour<=18: return True else: return False ``` ::: ### Dot or dash? Construct in python a function called morse that outputs "dot" if it recieves as a parameter a 0 and "dash" if recieves a 1. If receives anything else, it does nothing. :::spoiler ```python!= def morse(x): if x == 1: print("dash") if x == 0: print("dot") ``` Be aware that here we can use x or any other name for the parameter. Also we're not using the return statment nor the else because if we used it, then it would print something with inputs that are not 0. ::: ### Trace table 1 Given this code: ```python!= def functionA(x,y): return x-2*y def functionB(x): return functionA(10,x)-1 number = 3 otherNumber = functionA(number,1) if number > otherNumber: number = functionB(otherNumber) otherNumber = 3 else: otherNumber = 3 number = functionA(number, otherNumber) number = functionB(number) otherNumber = functionA(number, otherNumber) print(number) print(otherNumber) ``` Copy and complete the trace table (not only the output) | number | otherNumber | output | | -------- | -------- | -------- | | | | | Solution: :::spoiler | number | otherNumber | output | | -------- | -------- | -------- | | 3 | 1 | | | 7 | 3 | | | -5 | -11 | -5,-11 | ::: :::info :information_source: Remember to write the output _at the time_ that the output happens and not before! ::: ### Is it odd? This is a short one but is a __reminder__ of the modulus operand (% that returns the reminder of the division operation) Construct a function that given a number is going to tell if it's odd or not. (0 is not odd) The name of the function is `isOdd`. :::info You can find more info about the mod operator here https://stackoverflow.com/questions/17524673/understanding-the-modulus-operator ::: :::spoiler The step by step implementation ```python!= def isOdd(number) remainderIfWeDivideByTwo = number%2 answer = (remainderIfWeDivideByTwo == 1) return answer ``` The one liner solution ```python!= def isOdd(number) return number%2==1 ``` Both implementations are ok. ::: ### Is it disisible by 3? Construct a function that given an argument x (a number), returns if x is divisible by 3. Solution in the details :::spoiler ![image](https://hackmd.io/_uploads/ByCgqBPJbe.png) _Credit B.H._ ```python!= def isDivisibleBy3(number): return number%3==0 ``` ::: ### Which day is it? Sometimes we have codes for giving the information of which day it is. 0-> Monday 1-> Tuesday 2-> Wednesday ... (6 -> Sunday) Construct a function that given an argument (a number) it returns the string of the day it belongs. Solution in the details :::spoiler ```python!= def dayName(day): if day == 0: return "Monday" if day == 1: return "Tuesday" if day == 2: return "Wednesday" if day == 3: return "Thursday" if day == 4: return "Friday" if day == 5: return "Saturday" if day == 6: return "Sunday" return "no valid day" ``` Using list (in SL we didn't cover yet lists) ![image](https://hackmd.io/_uploads/B1PQoHPJWx.png) _credit M.M._ Using dictionaries (in SL we didn't cover yet dictionaries) ![image](https://hackmd.io/_uploads/S1Tq3rv1bl.png) _Credit B.H._ ::: ### Finding the middle ground Construct a function that given 2 numbers (x, y) it returns you the middle point. Solution in the details :::spoiler ![image](https://hackmd.io/_uploads/BJky6Bwy-x.png) _credit V.S._ ::: ### The yelling machine Construct a function that given a string it's going to output it 4 times. Solution in the details :::spoiler ```python!= def yellingMachine(x): print(x) print(x) print(x) print(x) ``` :::danger wrong answer (because returns instead of outputting) ![image](https://hackmd.io/_uploads/B1vHaSwybe.png) ::: . ::: ### The whatever machine Construct a function that given an input (a string) is going to return the message "whatever, here is your answer". Solution in the details :::spoiler ![image](https://hackmd.io/_uploads/Hya3TSwJWe.png) _credit M.V._ ::: ### Absolute value The absolute value of a number is that number is the distance from 0 of the number. Usually to calculate it we leave it like it is in case of positive and the positive version in case of the negative value. For example, the absolute value of 5 is 5 but the absolute value of -5 is 5. Construct in python a function called absoluteValue that, given a number is going to return its absolute value. :::info In python there is already an absolute value function `abs(n)` but it's a nice practice. ::: Solution in the details :::spoiler ```python!= def absoluteValue(x): if x >= 0: return x else: return -x ``` _Credit A.W._ ![image](https://hackmd.io/_uploads/S1ve1UvJ-l.png) _Credit B.H._ ::: ### Big, then square Construct in python a function that given 2 values is going to return the square of the biggest one. The name of the function is bigSquare Solution in the details :::spoiler ![image](https://hackmd.io/_uploads/BkGECSDybx.png) _Credit B.H._ ::: ### Square then big Construct in python a function that given 2 values is going to return the value of the biggest square of the parameters. The name of the function is SquareThenBig Solution in the details :::spoiler ![image](https://hackmd.io/_uploads/H1QUArvyWe.png) _Credit B.H._ ::: ### Differences between bigs and squares Explain the diferences between the last 2 exercises. //TO-DO ## Second batch of exercises ### Entering the disco In a disco there is a bouncer that is going to enforce the following instructions. If somebody is underage (less than 16), they don't enter. If somebody is altered (violent or visibly drunk), they don't enter. If somebody is gender "male" and they don't follow the dresscode, they don't enter. The age is stored in a number variable. Altered and dresscode are booleans (true for altered people or drunk and true for people that meet the dresscode). Gender is a String. a) Construct a function that returns if somebody enters or not given these conditions. The function is called validEntrance and it should recieve all the aforementioned arguments. //TO-DO b) Construct a function that outputs if somebody enters or not given these conditions. The function is called validEntrance and it should recieve all the aforementioned arguments. //TO-DO ### Energy company In a energy company the billing system works as follows: If the energy consumption in kWh (killo-Watts-hour) in a month is equal or bigger than 50 kWh, the bill will be a base of 20 euros plus each kWh is going to be charged 0.30 €. In the case that the energy consumption is less than 50 kWh, the bill will be a base of 20 euros and each kWh is going to be charged 0.20 €. So if the consumption is 15 kWh in a month, the bill will be 20+0.20*15 = 23 € in total. a) Determine the value of a bill of 60 KWh in a month. [1] :::info :information_source: This is a classic question of some IB exams, they give you some context and even before the actual coding part you have a question just to know if you got the context properly. They are usually 1 mark questions. ::: b) Construct in python a function called calculateBill that given the energy consumed in a month in kwh (consumption) is going to return the total amount of euros that needs to be paid. You may assume that the consumption is a number [4] //TO-DO ### Blood INC Blood INC is a company administrated by vampires. Vampires are very supersticious entities so they want to make sure that, when they hire somebody, their ID number should not be divisible by 7. Construct in python a function called luckyCheck that given a parameter called id is going to output “ALERT: DO NOT HIRE” in the case that id is divisible by 7. You may assume that the id is a number [2] Solution :::spoiler ```python!= def luckyCheck(id): if id%7 == 0: print("ALERT: DO NOT HIRE") ``` :::+ ### Exam day (also with modulus operator) We're going to decide when the students needs to come to exam and we want to be in 3 different groups. Their id is correlative. //TO-DO ```python!= def examDay(studentId): if studentId%3 == 0: return("Monday") if studentID%3 == 1: return("Wednesday") return("Friday") ``` :::success Modulus operator reminders: 7%2 -> 1 a%b -> c c < b ::: ### Trace table: electric boogaloo Given this python code: ![image](https://hackmd.io/_uploads/r11Yk6OJ-x.png) Copy and complete the following trace table [3] ![image](https://hackmd.io/_uploads/SJgV5kT_1Wl.png) Solution: :::spoiler | alice | bob | claudia | | -------- | -------- | -------- | | 1 | 2 | | | 5 | 2 | 5 | | 5 | 5 | 8 | | 25 | | | Working: line number 13: mystery(bob,alice) -> 5 line number 14: mystery2(5,2) -> 5 line number 16: (5!=5) != 2<5 -> False != True -> True so lines 17 and 18 happens and 20 and 21 doesn't (line 23 IS going to happen) line 23: mistery(mistery2(5,8), 5) -> mistery(10,5) ::: ### Exam exercises In a school they are going to introduce lockers that are going to have 4 different colours. The first locker (locker number 1) is going to be red, the second blue, the third green and the fourth one yellow. The fifth will be red again and so on. a. Determine the colour of the locker number 402 [1] Solution :::spoiler blue ::: b. Construct a function called lockerColour in python that given the number of the locker (x) is going to return as a string the corresponding colour. [3] :::spoiler ```python!= def lockerColour(x): if x%4 == 1: return "red" if x%4 == 2: return "blue" if x%4 == 3: return "green" if x%4 == 0: return "yellow" ``` With match solution: ```python!= def lockerColour(x): match x% 4: case 1: return "red" case 2: return "blue" case 3: return "green" case 0: return "yellow" ``` Using lists: ```python!= def lockerColour(x): colour = ["yellow", "red", "blue", "green"] return colour[x%4] ``` ::: ## References https://ellibrodepython.com/funciones-en-python https://www.w3schools.com/python/python_functions.asp More advanced: https://realpython.com/python-main-function/ https://realpython.com/python-modules-packages/