Table content of this notebook.
pass
statement and dropping else
daysInMonth
letterGrade
In the previous lecture, we discussed relational operators. They are binary operators (take two operands, one on each side) and evaluate to a boolean value of True
or False
. We discussed six operators: >
, >=
, <
, <=
, ==
, !=
.
Predict the values of the following expressions:
7 > 9
8 != 10
'bunny' < 'cat'
'do' >= 'dog'
'A' == 'a'
In the previous lecture, we also introduced three logical operators: and
, or
, and not
. The first two are binary operators (they take two operands) while not
is a unary operator (it takes only one operand). Usually, these operators take as their operands boolean values that are the output of relational expressions and predicates. For example:
10 > 5 and 10 < 20
'a' > 'b' or 'b' < 'c'
not 10 > 100 # Intepreted as not (10 > 100)
Finally, in lecture 6 we also saw that a predicate is simply a function that returns a boolean value. Here are some sample predicates:
def isFreezing(temp):
return temp <= 32
def isBoiling(deg):
return deg >= 212
def isWaterLiquidAtTemp(t):
return (not isFreezing(t)) and (not isBoiling(t))
Before running the examples below, try to first guess their output.
isFreezing(20)
isBoiling(100)
isWaterLiquidAtTemp(72)
An if
statement (also called a conditional statement) chooses between two branches based on a test value.
def absolute(n):
'''Return the absolute value of the number n'''
if n >= 0:
return n
else:
return -n
def classify(num):
'''Return a string indicating whether num is negative or not.'''
if num < 0:
return 'negative'
else:
return 'nonnegative'
absolute(-17)
absolute(111)
classify(-17)
classify(111)
A function with a conditional might print something.
def doWhenTemperature(temp):
if temp <= 65:
print("Put on a sweater or coat.")
else:
print("You can wear short sleeves today.")
doWhenTemperature(72)
doWhenTemperature(50)
Does doWhenTemperature
return anything?
print(doWhenTemperature(50))
def doILikeMissyElliott(rap, hiphop, pop):
"""A predicate to determine whether you like Missy Elliott"""
return rap or (hiphop and pop) # parentheses are unnecessary but used for clarity
def musicRecommender(rap, hiphop, pop):
"""Simple function that prints """
if doILikeMissyElliott(rap, hiphop, pop):
print("You should listen to Missy Elliott.")
else:
print("I would avoid Missy Elliott.")
musicRecommender(True, False, False)
musicRecommender(False, False, True)
musicRecommender(False, True, False)
def categorize(num):
'''This function has 3 statements in its body.
They are executed from top to bottom, one after the other.
'''
print('Categorizing', num)
if num % 2 == 0:
print("It's even")
else:
print("It's odd")
if num < 0:
'''This branch has 2 statements.'''
print("It's negative")
print("(That means it's less than zero)")
else:
print("It's nonnegative")
categorize(111)
categorize(-20)
pass
statement and dropping else
¶When we don't want to do anything in a conditional branch, we use the special pass
statement, which means "do nothing". (It's a syntax error to leave a branch blank.)
def warnWhenTooFast(speed):
if speed > 55:
print("Slow down! You're going too fast")
else:
pass # do nothing
warnWhenTooFast(75)
warnWhenTooFast(40)
It's OK to have an if
statement without an else
clause. In this case, the missing else
clause is treated as if it were a pass
statement.
def warnWhenTooFast2(speed):
if speed > 55:
print("Slow down! You're going too fast")
warnWhenTooFast2(75)
warnWhenTooFast2(40)
Below are two correct variants of the absolute
function defined above. Explain why they work.
def abs2(n):
'''returns the absolute value of n'''
result = n
if n < 0:
result = -n
return result
print(abs2(-17), abs2(42))
def abs3(n):
'''returns the absolute value of n'''
if n < 0:
return -n
return n
print(abs3(-17), abs3(42))
It often make sense to have a conditional statement nested inside the branch of another conditional.
Below we show variants of a function that returns the movie rating appropriate for a given age of movier goer. (If you want to learn more about film ratings, read this Wikipedia article.)
def movieAge1(age):
"""Returns the movie rating for the given age."""
if age < 8:
return 'G'
else:
if age < 13:
return 'PG'
else:
if age < 18:
return 'PG-13'
else:
return 'R'
def test_movieAge1(age):
print("age =", age, "; rating =", movieAge1(age))
test_movieAge1(5)
test_movieAge1(10)
test_movieAge1(15)
test_movieAge1(20)
It's possible to expression the same conditional logic with different nested conditionals:
def movieAge2(age):
"""Returns the movie rating for the given age."""
if age < 13:
if age >= 8:
return 'PG'
else:
return 'G'
else:
if age >= 18:
return 'R'
else:
return 'PG-13'
def test_movieAge2(age):
print("age =", age, "; rating =", movieAge2(age))
test_movieAge2(5)
test_movieAge2(10)
test_movieAge2(15)
test_movieAge2(20)
Python uses chained (multibranch) conditionals with if
, elif
s, and else
to execute exactly one of several branches.
def movieAge3(age):
"""Returns the movie rating for the given age."""
if age < 8:
return 'G'
elif age < 13:
return 'PG'
elif age < 18:
return 'PG-13'
else:
return 'R'
def test_movieAge3(age):
print("age =", age, "; rating =", movieAge3(age))
test_movieAge3(5)
test_movieAge3(10)
test_movieAge3(15)
test_movieAge3(20)
Remember: Only the first branch that evaluates to True
will be executed.
Important: As shown in the following example, the order of chaining conditionals matters!
def movieAgeWrong(age):
if age < 18:
return 'PG-13'
elif age < 13:
return 'PG'
elif age < 8:
return 'G'
else:
return 'R'
def test_movieAgeWrong(age):
print("age =", age, "; rating =", movieAgeWrong(age))
test_movieAgeWrong(5)
test_movieAgeWrong(10)
test_movieAgeWrong(15)
test_movieAgeWrong(20)
daysInMonth
¶Define a function named daysInMonth
that takes a month (as an integer) as the argument, and returns
the number of days in it, assuming the year is not a leap year.
Assume 1 is January, 2 is February, ..., 12 is December. If the month does not fall
between 1 and 12, return an error message as a string.
Make the function as concise as possible (group months by days, don't write 12 separate if-else clauses).
# Define your daysInMonth function below
# Your code here
def daysInMonth(month):
"""Returns number of days in a month or a message of error."""
if month == 2:
return 28
elif month < 1 or month > 12:
return "This is not a valid month."
elif month == 4 or month == 6 or month == 9 or month == 11:
return 30
else:
return 31
daysInMonth(4) # April
daysInMonth(8) # August
daysInMonth(2) # February
daysInMonth(13) # Error message
letterGrade
¶Extend the function letterGrade
from the weekly exercises to be a letterGradeAndMessage
function that also prints a message:
For all passing grades, it will initially print a message You passed!
and then return the grade letter.
For the failing grade F
, it will print the message Unfortunately, you failed.
and then return the letter 'F'.
You may use the print
statement only twice!
# Define your letterGradeAndMessage function below
# Your code here
def letterGradeAndMessage(score):
"""Returns the letter grade for a given score. Prints a message
too, based on pass/fail threshold.
"""
if score >= 60:
print("You Passed!")
if score >= 90:
return 'A'
elif score >= 80:
return 'B'
elif score >= 70:
return 'C'
elif score >= 60:
return 'D'
else:
print("Unfortunately, you failed.")
return 'F'
letterGradeAndMessage(85)
letterGradeAndMessage(58)
Having seen conditional statements, you may be tempted to use them in predicates. But most predicates can be defined without conditionals by using combinations of relational and logical operators. For example, compare the complicated and simplifed functions below:
def isFreezingComplicated(temp):
if temp <= 32:
return True
else:
return False
def isFreezingSimplified(temp):
return temp <= 32
print(isFreezingComplicated(20), isFreezingComplicated(72))
print(isFreezingSimplified(20), isFreezingSimplified(72))
def isPositiveEvenComplicated(num):
if num > 0:
if num % 2 == 0:
return True
return False
return False
def isPositiveEvenSimplified(num):
return num > 0 and num % 2 == 0
print(isPositiveEvenComplicated(42), isPositiveEvenComplicated(17), isPositiveEvenComplicated(-36))
print(isPositiveEvenSimplified(42), isPositiveEvenSimplified(17), isPositiveEvenSimplified(-36))
What happens if we compare numerical to string values?
In Python 3, numerical and string values are never equal. Furthermore, attempting to use >, >=, <=, or < will result in a TypeError.
Try to guess the outputs of these relational expressions before running the cells.
7 == '7'
10 < '10'
10000000 >= '0'
What happens if we compare numerical to boolean values?
In Python 3, in comparisons involving numbers and booleans, False is considered a synonym for 0 and True is considered a synonym for 1.
0 == False
1 == True
2 > True
1 > True
1 > False
0 > False
What to take away from the above examples: Python 3 allows the comparison of values of different types in some contexts. In general, it's better to stick with comparing values of the same type.
In Python, not
has surprising behavior when given a non-boolean operand:
not 111
not 0
not 'ab'
not ''
Truthy vs. Falsey Values:
What's going on in the above examples?
In Python, it turns out that in many contexts where a boolean is normally expected, 0 and 0.0 are treated like False
and all other numbers are treated like True
. So not 0
evaluates to True
and not 111
evaluates to False
.
Similarly, the empty string is treated like False
and nonempty strings are treated like True
. So not ''
evaluates to True
and not 'ab'
evaluates to False
.
In contexts where a boolean is normally expected, values that act like True
are called Truthy and values that act like False
are called Falsey. So 0, 0.0, ''
and False
are Falsey values, while all other numbers, strings, and booleans are Truthy.
Sadly, things are more complicated when it comes to testing equality:
0 == False
'' == False # Only 0 and 0.0 are considered equal to False
1 == True
17 == True # Only 1 and 1.0 are considered equal to True
'abc' == True
and
and or
also behave in surprising ways when their operands are not booleans:
111 or 230 # If first value is Truthy, return it; otherwise return second
0 or 230
0 or 0.0
'cat' or 'dog'
'' or 'dog'
0 or ''
111 and 230 # If first value is Falsey, return it; otherwise return second
0 and 230
0 and 0.0
'cat' and 'dog'
'' and 'dog'
0 and ''
The following definition of isVowel
doesn't work. Explain why!
def isVowelWrong(s):
low = s.lower()
return low == ('a' or 'e' or 'i' or 'o' or 'u')
isVowelWrong('a') # This works
isVowelWrong('b') # This works
isVowelWrong('e') # This doensn't work. Why?