# Functions and Booleans

## Think of a function as a black box

- the input to the box is a set of parameters
- the output from the box is a results
- the parameters may
**not**be modified by the function

### Some function examples

```
def say_hello(name):
print(f"Hello, {name}.")
say_hello("Ammon")
def make_money():
return 1000
money = make_money()
print(f"I have {money} dollars!")
def multiply_money(money):
money = money * 2
print(f"In here, I have {money} dollars")
multiply_money(money)
print(f"Wait, I still have {money} dollars?!")
```

```
Hello, Ammon.
I have 1000 dollars!
In here, I have 2000 dollars
Wait, I still have 1000 dollars?!
```

### If you need to modify a parameter, use return

- technically this creates a
*new*variable and returns that variable

```
def multiply_money(money):
money = money*2
return money
stuff = make_money()
more_stuff = multiply_money(stuff)
print(f"Aha, now I have {more_stuff} dollars!")
```

` Aha, now I have 2000 dollars!`

### Since an image is an object, we can modify its attributes

- pixels are attributes of an image, so we can modify them inside a function

```
from byuimage import Image
def darken(image):
for pixel in image:
pixel.red = pixel.red * 0.5
pixel.green = pixel.green * 0.5
pixel.blue = pixel.blue * 0.5
zion = Image("zion.jpg")
darken(zion)
zion.show()
```

## Divide and conquer

- This is a general problem-solving strategy
- Break a problem down into multiple, smaller parts
- Continue breaking parts down until you have a piece small enough for a function
- Each part gets its own, single-purpose function

## Functions and test cases

- we will write functions whose return value varies, depending on the parameters
- to test whether these functions work properly, we need to systematically test them

### Example function - bonus points

- look at student score and number of days it was submitted early
- for 1 or 2 early days, add 5%
- for 3 or more early days, add 10%
- can make a table of test cases

Score | Early Days | Final Score |
---|---|---|

90 | 0 | 90 |

90 | 2 | 94.5 |

90 | 5 | 99 |

80 | 1 | 84 |

70 | 3 | 77 |

### First try — which cases does it work for?

```
def bonus_points(score, early_days):
return score
print(bonus_points(90,0))
print(bonus_points(90,2))
print(bonus_points(90,5))
print(bonus_points(80,1))
print(bonus_points(80,3))
```

```
90
90
90
80
80
```

### Second try — which cases does it work for?

```
def bonus_points(score, early_days):
if early_days == 0:
return score
if early_days == 1 or early_days == 2:
return score*1.05
print(bonus_points(90,0))
print(bonus_points(90,2))
print(bonus_points(90,5))
print(bonus_points(80,1))
print(bonus_points(80,3))
```

```
90
94.5
None
84.0
None
```

- notice that if you fail to return a value for a certain case, then the function returns None

### Third try — which cases does it work for?

```
def bonus_points(score, early_days):
if early_days == 0:
return score
if early_days == 1 or early_days == 2:
return score*1.05
if early_days >= 3:
return score*1.1
print(bonus_points(90,0))
print(bonus_points(90,2))
print(bonus_points(90,5))
print(bonus_points(80,1))
print(bonus_points(80,3))
```

```
90
94.5
99.00000000000001
84.0
88.0
```

- due to the way computers represent floating-point numbers (like 90 x 1.1), there will be small differences due to approximations made with how numbers are stored in the computer.
- if you want to read about the details, see Floating Point Arithmetic: Issues and Limitations in the Python documentation

### What about negative early days (they turned it in late)?

```
def bonus_points(score, early_days):
if early_days == 0:
return score
if early_days == 1 or early_days == 2:
return score*1.05
if early_days >= 3:
return score*1.1
print(bonus_points(90,0))
print(bonus_points(90,2))
print(bonus_points(90,5))
print(bonus_points(80,1))
print(bonus_points(80,3))
print(bonus_points(80,-1))
```

```
90
94.5
99.00000000000001
84.0
88.0
None
```

- you want to be systematic and be sure to catch all cases

### Fourth try — which cases does it work for?

- observe — if we get past the first two cases, then by default there is no bonus
- we call this a
**pick-off**strategy — picking off cases and returning the result one-by-one

```
def bonus_points(score, early_days):
## small bonus
if early_days == 1 or early_days == 2:
return score*1.05
## big bonus
if early_days >= 3:
return score*1.1
## no bonus
return score
print(bonus_points(90,0))
print(bonus_points(90,2))
print(bonus_points(90,5))
print(bonus_points(80,1))
print(bonus_points(80,3))
print(bonus_points(80,-1))
```

```
90
94.5
99.00000000000001
84.0
88.0
80
```

### Fifth try — what if we want to penalize for late days?

- 5% off per day
- where do we add this code?

```
def bonus_points(score, early_days):
## small bonus
if early_days == 1 or early_days == 2:
return score*1.05
## big bonus
if early_days >= 3:
return score*1.1
## no bonus
return score
```

### Fifth try — what if we want to penalize for late days?

- 5% off per day
- where do we add this code?

```
def bonus_points(score, early_days):
## penalty for late days
if early_days < 0:
return score - score*(-early_days*0.05)
## small bonus
if early_days == 1 or early_days == 2:
return score*1.05
## big bonus
if early_days >= 3:
return score*1.1
## no bonus
return score
print(bonus_points(90,0))
print(bonus_points(90,2))
print(bonus_points(90,5))
print(bonus_points(80,1))
print(bonus_points(80,3))
print(bonus_points(80,-1))
print(bonus_points(80,-4))
```

```
90
94.5
99.00000000000001
84.0
88.0
76.0
64.0
```

## Boolean Values

- a boolean can be
`True`

or`False`

```
if bit.front_clear():
...
if early_days < 0:
...
while bit.get_color() == "red":
...
```

### Boolean operators

`==`

: compares two things and returns true if they are equal`!=`

: compares two things and returns true if they are*not*equal`<`

: returns true if the thing on the left is strictly less than the thing on the right`<=`

: checks for less than or equal to`>`

: checks for greater than`>=`

: checks for greater than or equal to

```
if early_days >= 3:
...
```

### Boolean operators

`and`

: combines values (this and this are both true)`or`

: this or this is true`not`

: this is not true

```
if temp < 50 or is_raining:
print('not going outside!')
if temp < 32 and is_raining:
print('yay snow!')
```

```
# what is the code to detect if the temp is over 70 and it's not raining?
temp = 80
is_raining = False
if temp > 70 and not is_raining:
print('Sunny and nice!')
```

` Sunny and nice!`

### don’t use `== True`

```
# do this
if is_raining:
print('raining')
# don't do this
if is_raining == True:
print('raining')
```

### write the `is_teen()`

function

```
def is_teen(n):
""" return True if n is in the range 13..19, inclusive. Otherwise return False. """
if n >= 13 and n <= 19:
return True
return False
print(is_teen(13))
print(is_teen(17))
print(is_teen(22))
```

```
True
True
False
```

## Using the Python Interpreter

You can open the `Python Console`

in Pycharm to access the Python interpreter.

You should see:

`>>>`

You can type any valid Python commands here! Try:

`n = 5`

`n == 6`

`n == 5`

`n != 6`

`n < 10`

`n < 5`

`n <= 5`

`n > 0`

- and so forth

### You can even define functions

Try working with your `is_teen()`

function:

```
def is_teen(n):
if n >= 13 and n <= 19:
return True
return False
is_teen(15)
```

### Another example

- write a function
`guessing(a, b, c)`

- you have three people guess a number from 1 to 10 (secretly from each other)
- if all three match, they win 10
- if any two match, they win 5
- otherwise, they win nothing

```
def guessing(a, b, c):
# fix this code
return 0
```