            # Conditionals & Booleans

Sue Evans & James MacGlashan

Adapted from the CS1 Course at Swarthmore College by Lisa Meeden

Hit the space bar for next slide

# Learning Outcomes

• Will know what a block of code is.
• An understanding of if statements and boolean expressions used with them.
• An ability to use if-else statements
• An ability to use if-elif-else statements
• An understanding of conditionals used with strings
• Be familiar with boolean operators
• Be familiar with boolean algebra, including DeMorgan's law
• Be familiar with Truth tables
• Understand the use of logical and to replace nested ifs
• Experience use of formatted output

# Control Structures

• Control Structures allow different lines of code to be executed depending on an evaluation of some expression.
• The most common conditional structure is the if structure.
• An if structure contains an expression and a block or body of code.
• When the expression is true, the block of code associated with the if statement is executed, otherwise it's skipped.

# If statements and code blocks

If statements take the form :

```if <condition>:
<block>
```
• Take note of the ':' after the <condition>.
• In Python, the ':' character, colon, is used to denote the start of a code block.
• All code in the block must be tab indented after the ':'.
• The first line that is not tabbed-in is the first line not included in that code block.
• ```if <condition>:
block-line-1
block-line-2
block-line-3
out-of-block-line-1
out-of-block-line-2
```
• Many other structures in Python also use code blocks in this same form where all lines after the ':' are tabbed in to be part of that block. These structures include functions and loops.
• Emacs indents automatically for you. When you push <enter> after typing the colon, emacs automatically tabs over for you to the starting position of the first line of the block. After typing that line, it indents for another line in that block. To stop indenting when the block is finished, use the backspace key.
• If statements and other structures that use blocks may be nested.
• This means the number of tab indents must increase with the level of nesting.
• ```if <condition1>:
block1-line-1
block1-line-2
if <condition2>:
block2-line-1
block2-line-2
out-of-block2-line-1-in-block1-line-3
out-of-block2-line-2-in-block1-line-4
out-of-block1-line-1
out-of-block1-line-2
out-of-block1-line-3
```
• Make sure you're consistent with your indentation.
• Although it's possible to indent in anyway (1 space, 3 spaces, 1 tab, etc..), it must be consistent, or python will return an error. Since emacs indents consistently for us, using it will keep us from having this kind of error when our code is in a file. You'll still have to be careful about indentation when using the interactive interpreter though.
• ```
>>> if True:
...     x = 1
...        y = 2
File "<stdin>", line 3
y = 2
^
SyntaxError: invalid syntax
>>>

```

# Boolean Expressions

• The <condition> part of the if statement represents a boolean expression that is either true or false.
• Expressions can be formulated using mathematical symbols to compare different values.
•  Python Symbol Meaning < is less than <= is less than or equal to == is equal to >= is greater than or equal to > is greater than != is not equal to

• When an expression is evaluated, it returns a boolean value in Python
• Examples:

```>>> x = 6
>>> y = 4
>>> x < y
False
>>> x <= y
False
>>> x == y
False
>>> x >= y
True
>>> x > y
True
>>> x != y
True
```
• Like any other value in Python, variables can store boolean values.
• ```>>> aBoolean = x > y
>>> print aBoolean
True
```
• Boolean values themselves are boolean expressions.
• Other data types can be converted to booleans by using bool(value).
• Integer or Float 0 become false, any other number becomes true.
• Empty strings become false, any other string becomes true.
• Empty lists become false, any other list becomes true.
```>>> bool(0)
False
>>> bool(1)
True
>>> bool(3)
True
>>> bool(-1)
True
>>> bool(0.0)
False
>>> bool(0.1)
True
>>> bool("")
False
>>> bool("hi")
True
>>> bool([])
False
>>> bool([1, 2])
True
```

# If statement execution

• When the condition of an if statement evaluates to true, the code block for that if statement is executed, otherwise it is skipped.
• ```>>> x = 6
>>> y = 4
>>> if x > y:
...     print "x is greater than y"
...
x is greater than y
>>> if x <= y:
...     print "x is less than or equal to y"
...
>>>
```
• The conditional "x > y" tests whether x is a greater value than y and if that is true, the string "x is greater than y" is printed.

# if-else

• If you want to handle cases when a condition fails as well as when it succeeds, use the else statement in conjunction with the if.
• else statements also contain a code block and are executed when the condition in the if statement is false, otherwise it is skipped.
• if-else statements take the form of :
• ```if <condition>:
<true-block>
else:
<false-block>
```
• We can revise the previous example as :
• ```>>> x = 6
>>> y = 4
>>> if x >= y:
...     print "x is greater than or equal to y"
... else:
...     print "x is less than y"
...
x is greater than or equal to y
```
• If we swap the values of x and y and rerun the if-else we get:
• ```>>> x = y
>>> y = x
>>> if x >= y:
...     print "x is greater than or equal to y"
... else:
...     print "x is less than y"
...
x is greater than or equal to y
```
• Something went wrong!
• The problem was in our swap. When we set x to y, x took on the value 4. Then when we set y to x, it again set it to 4 so that the values were equal
• To swap the values correctly, we'll need to use a temporary variable to hold the old value of x
• Here's what we should have written :
• ```>>> x = 6
>>> y = 4
>>> temp = x
>>> x = y
>>> y = temp
>>> if x >= y:
...     print "x is greater than or equal to y"
... else:
...     print "x is less than y"
...
x is less than y
```
• It turns out that even though most languages require the use of a third variable (conventionally called temp) to perform a swap, Python has a short-cut built into the language for this called simultaneous assignment.
• ```>>> x = 6
>>> y = 4
>>> x, y = y, x
>>> if x >= y :
...     print "x is greater than or equal to y"
... else:
...     print "x is less than y"
...
x is less than y
>>>
```

# Example Program Using if-else

• Let's write a program that analyzes the kinds of characters in a string
• ```
# Filename:    ifelse.py
# Written by:  Sue Evans
# Date:        7/29/09
# Section:     All
# Email:       bogar@cs.umbc.edu
#
# This program illustrates the use of the if-else
# structure working with strings that can contain
# any of the printable characters.  It counts the
# number of letters and other characters in the
# input string.

import string

def main():

# give an explanation of the program
print
print "This program counts the letters and other"
print "characters in a message."
print

# initialize the counters
letters = 0
others = 0

# get a string from the user
message = raw_input("Enter your message : ")

# change the message to have only upper case letters
allCaps = string.upper(message)

# loop over the string counting letters and others
for char in allCaps :

# get ASCII value of char
value = ord(char)

# if char is a letter increment letters
if value >= 65 :
if value <= 90 :
letters = letters + 1
# make sure we get others > 90
else :
others = others + 1
# otherwise increment others < 65
else :
others = others + 1

# calculate total number of characters
total = letters + others

# print the results
print
print "Total characters : ", total
print "Letters : ", letters
print "Other : ", others
print

main()

```
• Let's run it.
• ```
linuxserver1.cs.umbc.edu python ifelse.py

This program counts the letters and other
characters in a message.

Enter your message : This is my 1st message.

Total characters :  23
Letters :  17
Other :  6

linuxserver1.cs.umbc.edu

```

• What if we want to count the number of digits too ?

If the character isn't a letter, then it is either a digit or it's some other kind of character. So inside the else part, we could put another if-else structure. Let's try it :
• ```
# Filename:    ifelse2.py
# Written by:  Sue Evans
# Date:        7/29/09
# Section:     All
# Email:       bogar@cs.umbc.edu
#
# This program illustrates the use of the if-else
# structure working with strings that can contain
# any of the printable characters.  It counts the
# number of letters, digits and other characters
# in the input string.

import string

def main():

# give an explanation of the program
print
print "This program counts the letters, digits"
print "and other characters in a message."
print

# initialize the counters
letters = 0
digits = 0
others = 0

# get a string from the user
message = raw_input("Enter your message : ")

# change the message to have only upper case letters
allCaps = string.upper(message)

# loop over the string counting character types
for char in allCaps :

# get ASCII value of char
value = ord(char)

# if char is a letter, increment letters
if value >= 65 :
if value <= 90 :
letters = letters + 1
# make sure we get others > 90
else :
others = others + 1

# otherwise
else :
# if it's a digit, increment digits
if value >= 48 :
if value <= 57 :
digits = digits + 1
# make sure we get others 58 - 64
else :
others = others + 1
#otherwise increment others < 48
else :
others = others + 1

# calculate total number of characters
total = letters + digits + others

# print the results
print
print "Total characters : ", total
print "Letters : ", letters
print "Digits : ", digits
print "Other : ", others
print

main()

```
• Let's run this new version
• ```
linuxserver1.cs.umbc.edu python ifelse2.py

This program counts the letters, digits
and other characters in a message.

Enter your message : This is the 2nd 201 message.

Total characters :  28
Letters :  18
Digits :  4
Other :  6

linuxserver1.cs.umbc.edu

```
• What if we wanted to also count the number of spaces ?

We'd have to put another if-else inside the innermost else. This is getting tedious and confusing. It's also true that the indentation is getting deeper and deeper as we add more kinds of characters to count ... There has to be a better way !

# if-elif-else

• In the previous example it was cumbersome to nest an if inside an else block. If there were more than 3 cases, it would get even cumbersome
• To remedy this problem there is also an if-elif-else structure
• ```if <condition1>:
<case1-block>
elif <condition2>:
<case2-block>
else:
<default-block>
```
• In this structure the first if statement is evaluated and if it is true, its block is executed and then it skips to the bottom
• If the first condition is false, it checks the condition in the next elif (which stands for "else-if")
• If the condition in the elif is true it executes its block, and then skips to the bottom
• If the elif condition is false, then the else block is executed
• An arbitrary number of elif statements can be added following the first if
• The flow of this can be thought of by progressively nesting if-else blocks in the previous else block
• An else statement does not have to be included if there is no default state producing a structure like this:
• ```if <condition1>:
<case1-block>
elif <condition2>:
<case2-block>
```
• Here's an example where if-elif-else can be useful is getting letter grades for students' numeric grades.
• ```
...     print 'A'
...     print 'B'
...     print 'C'
...     print 'D'
... else:
...     print 'F'
...
B

```
• Using this technique, we can now also modify our previous character-counting code with an if-elif-else control and even add counting spaces to it.
• ```
# Filename:    ifelifelse.py
# Written by:  Sue Evans
# Date:        7/29/09
# Section:     All
# Email:       bogar@cs.umbc.edu
#
# This program illustrates the use of the if-else
# structure working with strings that can contain
# any of the printable characters.  It counts the
# number of letters, digits, spaces and other
# characters in the input string.

import string

def main():

# give an explanation of the program
print
print "This program counts the letters, digits,"
print "spaces and other characters in a message."
print

# initialize the counters
letters = 0
digits = 0
spaces = 0
others = 0

# get a string from the user
message = raw_input("Enter your message : ")

# change the message to have only upper case letters
allCaps = string.upper(message)

# loop over the string counting character types
for char in allCaps :

# get ASCII value of char
value = ord(char)

# if char is a letter, increment letters
if value >= 65 :
if value <= 90 :
letters = letters + 1
# make sure we get others > 90
else :
others = others + 1

# if it's a digit, increment digits
elif value >= 48 :
if value <= 57 :
digits = digits + 1
# make sure we get others 58 - 64
else :
others = others + 1

# if it's a space, increment spaces
elif value == 32 :
spaces = spaces + 1

# if none of the above, increment others < 48
else :
others = others + 1

# calculate total number of characters
total = letters + digits + spaces + others

# print the results
print
print "Total characters : ", total
print "Letters : ", letters
print "Digits : ", digits
print "Spaces : ", spaces
print "Other : ", others
print

main()

```
• When we run this new version we get :
• ```linuxserver1.cs.umbc.edu python ifelifelse.py

This program counts the letters, digits,
spaces and other characters in a message.

Enter your message : This is the 3rd 201 lecture message.

Total characters :  36
Letters :  25
Digits :  4
Spaces :  6
Other :  1

linuxserver1.cs.umbc.edu

```

# Exercise:

The National Weather Service has 5 categories to describe hurricanes, shown in the following chart:

Category Wind Speed
1 - Minimum 74 - 95 mph
2 - Moderate 96 - 110 mph
3 - Extensive 111 - 130 mph
4 - Extreme 131 - 155 mph
5 - Catastrophic greater than 155 mph

Write Python code that will get the current wind speed from the user and will print out if this is a hurricane and which category number it is.

HINT: Make use of the fact that there are no breaks in the values.
There is no need to use the and or or operators.

# String Conditionals

• In Python, the operators in boolean expressions, aren't restricted to numbers.
• Boolean operators can also work on strings and other more complex types.
• For strings the operators take on the following meanings :
•  Python Symbol Meaning < First string comes alphabetically before second <= First string comes alphabetically before second or is equivalent to it == The two strings are the same >= First string comes alphabetically later than second or is equivalent to it > First string comes alphabetically later than second != Strings are not the same

• Capitalized strings come before any lower case strings, since the ASCII value of capital letters have a smaller numeric value than those of lower-case letters
• This means "Cb" < "ab"
• Using these operators, we can run menus and handle other forms of queries from users.
• The example below prints the points value for a playing card.
• ```>>> cardName = raw_input("Enter the card's name : ")
Enter the card's name : Queen
>>> if cardName == "Ace":
...     print 1
... elif cardName == "King":
...     print 13
... elif cardName == "Queen":
...     print 12
... elif cardName == "Jack":
...     print 11
... else:
...     print int(cardName)
...
12
```

# Boolean Operators

• Consider the scenario where you have 2 points denoted by x1, y1 and x2, y2 and you want to see if they are the same
• To do this use you can use the following code :
• ```if x1 == x2:
if y1 == y2:
#points are the same
else:
#points are different
else:
#points are different
```
• Boolean operators allow for more complex structures like the one above to be evaluated in a single expression
• ```if x1 == x2 and y1 == y2:
#points are the same
else:
#points are different
```
• The and operator is just one boolean operator that means the expressions on both sides must be true for the entire expression to be true
• Other operators include or and not
• Here are the Truth Tables for and, or and not
• P Q P and Q
T T T
T F F
F T F
F F F

P Q P or Q
T T T
T F T
F T T
F F F

P not P
T F
F T

• Order of operator precedence from high to low is: not, and, or
• Expressions may also use parentheses to change the order of operations
• P Q not P and Q
T T F
T F F
F T T
F F F

P Q not (P and Q)
T T F
T F T
F T T
F F T

• These basic principles can be used to construct more complex operators
• Exclusive-or = (P or Q) and not (P and Q)

# Boolean Algebra

• You can use Boolean algebra to manage and reduce complex expressions.
• The and and or operators distribute over each other.
• a or (b and c) == (a or b) and (a or c)
• a and (b or c) == (a and b) or (a and c)
• DeMorgan's Law distributes an outer 'not' by negating (not-ing) each of the components and flipping ands to ors and ors to ands.
• not(a or b) == (not a) and (not b)
• not(a and b) == (not a) or (not b)

# Character Counting Revisited

• Now that we know about logical and, we can simplify our character-counting program.
• When trying to determine if a character is a letter or a digit, we had the following code :
• ```        # if char is a letter, increment letters
if value >= 65 :
if value <= 90 :
letters = letters + 1
# make sure we get others > 90
else :
others = others + 1

# if it's a digit, increment digits
elif value >= 48 :
if value <= 57 :
digits = digits + 1
# make sure we get others 58 - 64
else :
others = others + 1
```
• We can simplify this code considerably by using and
• ```        # if char is a letter, increment letters
if value >= 65 and value <= 90 :
letters = letters + 1
# if it's a digit, increment digits
elif value >= 48 and value <= 57 :
digits = digits + 1
```
• Here's the new version of the character counter program
• ```
# Filename:    ifelifelse2.py
# Written by:  Sue Evans
# Date:        7/29/09
# Section:     All
# Email:       bogar@cs.umbc.edu
#
# This program illustrates the use of the if-else
# structure working with strings that can contain
# any of the printable characters.  It also uses
# logical and.  The program counts the number of
# letters, digits, spaces and other characters in
# the input string.

import string

def main():

# give an explanation of the program
print
print "This program counts the letters, digits,"
print "spaces and other characters in a message."
print

# initialize the counters
letters = 0
digits = 0
spaces = 0
others = 0

# get a string from the user
message = raw_input("Enter your message : ")

# change the message to have only upper case letters
allCaps = string.upper(message)

# loop over the string counting character types
for char in allCaps :

# get ASCII value of char
value = ord(char)

# if char is a letter, increment letters
if value >= 65 and value <= 90 :
letters = letters + 1
# if it's a digit, increment digits
elif value >= 48 and value <= 57 :
digits = digits + 1
# if it's a space, increment spaces
elif value == 32 :
spaces = spaces + 1
# if none of the above, increment others
else :
others = others + 1

# calculate total number of characters
total = letters + digits + spaces + others

# print the results
print
print "Total characters : ", total
print "Letters : ", letters
print "Digits : ", digits
print "Spaces : ", spaces
print "Other : ", others
print

main()

```
• Since we've changed our code, we should run it again to make sure it still works.
• ```
linuxserver1.cs.umbc.edu python ifelifelse2.py

This program counts the letters, digits,
spaces and other characters in a message.

Enter your message : This seems like the 100th time we've run this.

Total characters :  46
Letters :  33
Digits :  3
Spaces :  8
Other :  2

linuxserver1.cs.umbc.edu

```
• It's also bothering me that our output looks sloppy, so before we put the character counter out to pasture, let's try to clean up the output.
• I think it would look better if all the numbers were lined up in a column and then have the total printed beneath the individual counts, like an addition problem.
• Our code for the output currently looks like :
• ```
# print the results
print
print "Total characters : ", total
print "Letters : ", letters
print "Digits : ", digits
print "Spaces : ", spaces
print "Other : ", others
print

```
• Let's change it to :
• ```
# print the results
print
print "Letters :", letters
print " Digits :", digits
print " Spaces :", spaces
print "  Other :", others
print "            ---"
print "  Total :", total
print

```
• Let's see what the output looks like now.
• ```
linuxserver1.cs.umbc.edu python format.py

This program counts the letters, digits,
spaces and other characters in a message.

Enter your message : Here's the 101st time !!!

Letters : 14
Digits : 3
Spaces : 4
Other : 4
---
Total : 25

linuxserver1.cs.umbc.edu

```
• @&\$#*&!!!
• We really wanted the 3 and the 4s in the units column, not the tens column.
• We can format our output as in this program snippet :
• ```
# print the formatted results
print
print "Letters : %3d" % (letters)
print " Digits : %3d" % (digits)
print " Spaces : %3d" % (spaces)
print "  Other : %3d" % (others)
print "          ---"
print "  Total :%4d" % (total)
print
```
• In the print statement we can indicate that we want the value of a variable printed right-justified within a certain width. The type of the variable also needs to be specified.
• The %3d being used in the string of the print statements above means to print the value of an integer in base 10, decimal,-
the d stands for decimal integer. The 3 says the field width we want is 3. Numbers are right-justified.
• Notice that I've moved the line to the left and have used %4d for the total. I'm assuming that the user won't type an extremely long message, but I'm allowing there to be up to 999 letters before the formatting will break. If there were 999 letters, there probably will exist at least one other kind of character, which means the total will have to have a width of 4.
• ```
linuxserver1.cs.umbc.edu python format2.py

This program counts the letters, digits,
spaces and other characters in a message.

Enter your message : It's the 1000th time !!!!!

Letters :  12
Digits :   4
Spaces :   4
Other :   6
---
Total :  26

linuxserver1.cs.umbc.edu

```
• Success !