# debugging tip: add a print before an if to clarify the problem
# Also try different values for team
# print(team == "Gophers" or "Hawkeyes" or "Bulldogs")
```
%% Cell type:code id: tags:
``` python
# Warmup 2: Test this function by performing several calls.
# Does it work? How can it be fixed? How can it be made better?
defprint_month(month):
'''Print a month (given as an integer) as a string. 1 is Jan, 2 is Feb, etc.'''
ifmonth==1:
print("Jan")
ifmonth==2:
print("Feb")
ifmonth==3:
print("Mar")
ifmonth==4:
print("Apr")
ifmonth==5:
print("May")
ifmonth==6:
print("Jun")
ifmonth==7:
print("Jul")
ifmonth==8:
print("Aug")
ifmonth==9:
print("Sep")
ifmonth==10:
print("Oct")
ifmonth==11:
print("Nov")
ifmonth==12:
print("Dec")
else:
print("N/A")
# TODO Write your tests here.
```
%% Cell type:markdown id: tags:
## Reminder
* using conditional execution:
```
if condition:
# if's body (block of code that executes when condition is true)
```
* using alternate execution:
```
if condition:
# if's body (block of code that executes when condition is true)
else:
# else block (code executes when condition is false)
```
* using chained conditionals (at most one body block will be executed)
```
if condition1:
# body1
elif condition2:
# body2
elif condition3:
# body3
...
else: (optional)
# else body
```
%% Cell type:markdown id: tags:
# Conditionals 2
## Readings
-[Python for Everybody, 4.6 - end (skip 4.7)](https://runestone.academy/ns/books/published//py4e-int/conditional/toctree.html)
## Learning Objectives
After this lecture you will be able to...
- Read and write nested conditional statements
- Define, state reasons for, and provide examples of refactoring
- Refactor code containing conditional statements into boolean expressions
- Recognize and utilize some common refactoring patterns
%% Cell type:markdown id: tags:
## Read and Write Nested Conditional Statements
Conditional statements can contain multiple lines of code in the body of the conditional. One way to use this is to have a conditional statement nested inside of another conditional statement:
```
if condition1:
if condition2:
body1
else:
body2
else:
if condition3:
body3
else:
body4
```
### Example
Perhaps you have heard the statement "If it moves and it shouldn't use duct tape, if it doesn't move and it should, use WD-40". The diagram below shows a flowchart of this situation and the Python code below that attempts to implement this situation with the function `fix(moves,should)`. Try running the function using different input values.
%% Cell type:markdown id: tags:

%% Cell type:code id: tags:
``` python
# Nesting Example 1: Fixing it
deffix(moves,should):
ifmoves:
ifshould:
return"good"
else:
return"duct tape"
else:
ifshould:
return"WD-40"
else:
return"good"
print(fix(moves=True,should=False))
# TODO add additional calls to the fix() function
```
%% Cell type:markdown id: tags:
### You Try It
Finish the function `stop_light(color,distance)` where the behavior of the function is shown in the diagram below. The function should return a string saying what the driver should do as shown in the diagram.
%% Cell type:markdown id: tags:

%% Cell type:code id: tags:
``` python
defstop_light(color,distance=100):
"""given color red/yellow/green and distance in feet, return what to do as a str"""
pass
print(stop_light("green",20))
print(stop_light("red",30))
print(stop_light("red",100))
print(stop_light("yellow",20))
print(stop_light("yellow",60))
```
%% Cell type:markdown id: tags:
## Refactoring
What is it?
- Improving/rewriting parts of a program without changing its behavior.
- Like a re-wording of a recipe without changing it
Why do it?
- Make it easier to read and understand the code & what it's doing
- Sometimes to make code run faster
Principles of good refactoring:
-**Don't change the program's behavior!**
- The program should end up more readable than it started
- Use knowledge of if/else, and/or/not, ==, !=, etc.
%% Cell type:markdown id: tags:
### Example
Here is a refactored version of the `fix()` function. Using if/elif/else structure makes it clearer and easier to debug because there is no nesting of conditionals (where it is easy to make mistakes or forget a nested conditional).
Test that its behavior is the same as the original fix() function.
%% Cell type:code id: tags:
``` python
deffix_refactor(moves,should):
ifmovesandshould:
return"good"
elifmovesandnotshould:
return"duct tape"
elifnotmovesandshould:
return"WD-40"
else:
return"good"
## TODO test that the fix_refactor has the same behavior as fix()
```
%% Cell type:markdown id: tags:
### You Try It
Think about another way to write the `stop_light()` function. Can you make it clearer by refactoring?
%% Cell type:code id: tags:
``` python
defstop_light_refactor(color,distance=100):
"""given color red/yellow/green and distance in feet, return what to do as a str"""
pass
## Now test that its behavior is the same as the stop_light() function.
print(stop_light_refactor("green",20))
print(stop_light_refactor("red",30))
print(stop_light_refactor("red",100))
print(stop_light_refactor("yellow",20))
print(stop_light_refactor("yellow",60))
```
%% Cell type:markdown id: tags:
Refactoring can involve lots of ways of rewriting code. Below is an example of a `check_combination()` function that should return True if the combination is exactly 32, 17, 55 and False otherwise. It uses many nested if statements and only one of the multiple branches returns True. Can you think about how this function could be re-written to make it clearer?
%% Cell type:code id: tags:
``` python
# Refactoring Example 1: too many nested if's
# combination lock function
defcheck_combination(a,b,c):
ifa==32:
ifb==17:
ifc==55:
returnTrue
else:
returnFalse
else:
returnFalse
else:
returnFalse
## TODO Write some checks that it returns true only if the values are exactly 32, 17, 55
```
%% Cell type:markdown id: tags:
Here is an attempt to refactor the function, but it doesn't work properly. Write some tests to show that its behavior is not the same as the check_combination() function?
%% Cell type:code id: tags:
``` python
# show an incorrect way to refactor combo
# give evidence that it does not give the same results
defbad_combo(a,b,c):
returna==32orb==17orc==5
# TODO write some tests!
```
%% Cell type:markdown id: tags:
### You Try It
Now give it a try. Finish the `refactor_combo()` function so its behavior is exactly the same as check_combination(). Try and do it without using a single conditional. Also, write tests to prove that its behavior is the same.
%% Cell type:code id: tags:
``` python
# correctly refactor combo with a new name - below
defrefactor_combo(a,b,c):
pass
# TODO write some tests!
```
%% Cell type:markdown id: tags:
### Another Refactoring Example
Here is another example where you can refactor. The function `check_different(b1,b2)` returns True only if the boolean parameters `b1` and `b2` are different values. The code uses an if/elif method for solving the problem.
%% Cell type:code id: tags:
``` python
# Refactoring Example 2: too much code
defcheck_different(b1,b2):
ifb1==Trueandb2==False:
returnTrue
elifb1==Falseandb2==True:
returnTrue
elifb1==Trueandb2==True:
returnFalse
elifb1==Falseandb2==False:
returnFalse
print(check_different(True,False))
print(check_different(False,False))
print(check_different(False,True))
print(check_different(True,True))
```
%% Cell type:markdown id: tags:
### You Try It
Finish the `check_different_refactor(b1,b2)` so that its behavior is the same as check_different() and do it without using any conditional statements.
%% Cell type:code id: tags:
``` python
defcheck_different_refactor(b1,b2):
pass
## Also write tests to prove that its behavior hasn't changed
```
%% Cell type:markdown id: tags:
## Common Refactoring Patterns
There are some common refactoring patterns that you can recognize and use to restructure your code. Take, for example, the `or` operator. Imagine needing to `or` together three boolean values. There are multiple ways that this can be done that will result in the same before. Take a look at the multiple implementations of the `or2()` function to see three different ways that this can be done.
%% Cell type:code id: tags:
``` python
defor2(cond1,cond2,cond3):#Version 1
returncond1orcond2orcond3
## now use the function to see its behavior
print(or2(False,True,False))
## TODO: add more tests of the function
```
%% Cell type:code id: tags:
``` python
defor2(cond1,cond2,cond3):#Version 2
rv=False
rv=rvorcond1
rv=rvorcond2
rv=rvorcond3
returnrv
##TODO: add tests to demonstrate this version behaves the same as the previous version
print(or2(False,True,False))
```
%% Cell type:code id: tags:
``` python
defor2(cond1,cond2,cond3):#Version 3
ifcond1:
returnTrue
elifcond2:
returnTrue
elifcond3:
returnTrue
else:
returnFalse
##TODO: Again, test that its behavior is the same
print(or2(False,True,False))
```
%% Cell type:markdown id: tags:
What are the advantages or disadvantages of these different versions of the `or2()` function. Some methods may write less code while other methods may seem more understandable.
### You Try It
Try refactoring the `and2()` function to create other versions that have the same behavior.
%% Cell type:code id: tags:
``` python
defand2(cond1,cond2,cond3):
returncond1andcond2andcond3
print(and2(True,True,False))
```
%% Cell type:code id: tags:
``` python
##TODO: write an alternate way of implementing this same behavior
defand2(cond1,cond2,cond3):
pass
```
%% Cell type:markdown id: tags:
## Summary
You have practiced creating **nested conditionals** and you have learned about **refactoring**. You have practiced refactoring multiple functions including ways of flattening nested conditionals and removing conditionals all together.
**After Lecture Practice**
You are encouraged to continue practicing refactoring. Read the slides linked to on the course schedule to see more examples of refactoring and try the problems below taken from previous exams to continue practicing this important skill.
%% Cell type:code id: tags:
``` python
# Refactoring Practice 1: recognizing equivalent code
# Exam 1 Fall 2020
defg(x,y):
ifx:
ify:
returnTrue
else:
returnFalse
else:
returnFalse
#which of the following will give the same result in all cases, as g(b1,b2) ?
# a.) b1 != b2
# b.) b1 and b2
# c.) b1 == b2
# d.) b1 or b2
print(g(True,False))
print(g(False,True))
print(g(True,True))
print(g(False,False))
```
%% Cell type:code id: tags:
``` python
# Refactoring Practice 2:
defh(x,y):
ifx:
returnFalse
else:
ify:
returnFalse
else:
returnTrue
print(h(True,False))
print(h(False,True))
print(h(True,True))
print(h(False,False))
# which of the following will give the same result in all cases, as h(b1,b2) ?
# a.) b1 != b2
# b.) b1 and b2
# c.) b1 == b2
# d.) not b1 and not b2
```
%% Cell type:code id: tags:
``` python
# Refactoring Practice 3:
# Consider the following code
defrefactor(x,y):
ifx:
returnTrue
elify:
returnTrue
else:
returnFalse
print(refactor(True,False))
print(refactor(False,True))
print(refactor(True,True))
print(refactor(False,False))
# what is the best way to refactor the body of the function ?