Week 4: Strings, Booleans, Branching
Monday
More String Operations
You’ve seen several instances of strings already this semester, and you’ve likely used string concatenation to build up a string. There are many other useful string operations. Here are some highlights:
-
length. To get the length of a string, use the
len
command e.g.len("cs21") = 4
-
indexing. Access a single character in a string using its position indexing from zero. For example, if
name="Punxsutawney"
, thenname[1]
is the string value"u"
. -
concatenation. Concatenate with the
+
operator."hello" + "world"
produces"helloworld"
Accumulator Pattern - Strings
Just as we saw with numbers, you can use a for
loop and the accumulator
pattern to build strings. To start with an empty string, initialize a variable
with two quote marks that have nothing inside them (not even a space):
result = ""
You can then build up the result
string by accumulation with the +
operator. Let’s practice together by writing a program interests.py
that
asks the user for three things they like and then prints them back:
$ python3 interests.py Tell me three things you like! Thing 1: plants Thing 2: puppies Thing 3: CS 21 You like: plants puppies CS 21
Exercise: str_practice.py
Open str_practice.py
to complete four tasks and a couple of
extensions if you desire. Be sure to incrementally develop — complete
one task, run your program to see if that tasks works, and then move
onto the next. Tasks 4 and bonus will require for
loops and
accumulators.
$ python3 str_practice.py
Task 1:
Enter a first name: Simone
Enter a last name: Biles
Hello Simone Biles
Task 2:
There are 11 characters in this name
Task 3:
Initials: S.B.
BONUS:
Last initials: e.s.
Task 4:
S
i
m
o
n
e
S
Si
Sim
Simo
Simon
Simone
Boolean Logic and Relational Operators
Our programs in the first week were entirely sequential. Each statement was
processed immediately after the preceding line. In week two, we added the for
loop to allow us to repeat a task a fixed number of times. This week we will
introduce a new type, the Boolean type and show how to use it with branching
or decision structures to optionally run code based on various conditions.
Booleans and conditionals represent another computational tool we will use
throughout the semester to design algorithms for problems.
The Boolean or bool
type can only hold two possible values: True
or
False
. Note in Python, both of these values begin with an upper case letter
and the values do not have quotes around them. The value "True"
(with quotes)
is a string, not a Boolean.
One way to generate a Boolean value is to use one of the relational operators
listed below. For example, the operator <
compares two variables or expressions
left < right
. If the value of left
is smaller than right
, the expression left <
right
evaluates to True
, otherwise, the answer is False
.
Python’s relational operators are:
Operator | Meaning |
---|---|
< |
less than |
<= |
less than or equal to |
> |
greater than |
>= |
greater than or equal to |
== |
equal to |
!= |
not equal to |
Note that to check if two expressions are equal, you must use the ==
, e.g.,
x == 7
. Using x = 7
in Python has a different semantic meaning — it
performs a variable assignment and stores the value of 7 in the container
labeled x.
Exercise: practice relational operators
What are the bool
values that result from the following expressions? Assume
x = 10
. First, try to predict the value, then you can check your answers in
an interactive Python shell by typing python3
in the terminal.
x < 10
x >= 10
x != 15
(x + 15) <= 20
(x % 2) == 1
Note: %
is the mod or remainder operator. x % y
returns the remainder when
x
is divided by y
using integer division.
Branching with if
Programmers use branching, or conditional statements, to run different code
based on the state of the program. The simplest form of branching is an if
statement:
if <condition>:
<body>
Here, <condition>
should be a statement that evaluates to a Boolean value.
The code inside the <body>
only runs if the condition is True
. Here’s an
example program that warns you only if the temperature is below freezing:
def main():
temp = int(input("Enter temperature: "))
if temp < 32:
print("Freezing temperatures; be sure to wear a coat!")
print("Have a great day!")
main()
Note the use of the :
as we saw at the end of for
loops and the main()
function. Like those constructs, the <body>
of an if
must be indented to
indicate that it should execute together as part of the if
statement.
Other Branching Structures
In addition to the basic if
statement, Python supports two additional
variants: if/else
and if/elif/else
. The general form of the if/else
is:
if <condition>:
<body>
else:
<else-body>
Again, if the <condition>
evaluates to True
, Python executes the code in
<body>
. However, if the condition is False
, Python executes the code in
<else-body>
instead. Regardless of the value of <condition>
, exactly one
of <body>
or <else-body>
will run, but not both. It is possible to have an
if
with no else
, but any else
must be paired with a matching if
statement.
We could modify the program above to print a different message if temp
is
above freezing. Regardless of the temp
value, the program will always print
Have a great day!
since this message is printed outside the body of either
the if
or the else
as noted by the indentation.
def main():
if temp < 32:
print("Freezing temperatures; be sure to wear a coat!")
else:
print("Spring is on its way!")
print("Have a great day!")
main()
The final, most complex branching variant is the if/elif/else
:
if <cond-1>:
<body-1>
elif <cond-2>:
<body-2>
elif <cond-3>:
<body-3>
...
else:
<else-body>
All of these statements work together as one large decision block. Python will
first evaluate <cond-1>
and if it’s True
, it will execute <body-1>
then
skip over the remaining bodies in the block. If <cond-1>
is False
, Python
will next evaluate <cond-2>
. If that is True
, it will execute <body-2>
and then skip over all the remaining bodies in the block. We can continue to
add more elif
conditions and bodies, but each condition will only be
evaluated if all the other previous conditions were False
. Finally if all
the condition checks evaluate to False
, Python executes the <else-body>
, if
there is one. You can have an if/elif/elif/…
with no final else
.
In summary, a decision block has a mandatory if <condition>:
at the
beginning, and optional else:
at the end, and zero or more elif <condition-k>:
statements in the middle.
Wednesday
Exercise: practice if statements
Practice if/else
statements by writing a block of code (in
cs21/inclass/w04-boolean/voting.py
) that determines if a person’s age makes them
eligible to vote (18 or older on election day).
Some potential output might look like:
$ python3 voting.py Enter your age on election day: 20 You are eligible to vote $ python3 voting.py Enter your age on election day: 18 You are eligible to vote $ python3 voting.py Enter your age on election day: 2 You can't vote this year You will need to wait 16 years
Code tracing is when you run through code in your head and try to determine the result. I have provided three blocks (the last purposefully being harder than the other two). What will each of these blocks do? Do they give different results, or are some of them equivalent in terms of what they print?
#Block 1
if temp >= 60:
print("No coat is needed")
if temp >= 40:
print("Spring jacket")
#Block 2
if temp >= 60:
print("No coat is needed")
elif temp >= 40:
print("Spring jacket")
#Block3
if temp >= 40:
if temp >= 60:
print("No coat is needed")
else:
print("Spring jacket")
Logical Operators
In many programs, it’s convenient to ask compound questions or require multiple
conditions be True
before executing some code. In these cases, we can join to
questions together using a logical operator:
Operator | Meaning |
---|---|
and |
both boolean expressions must be true |
or |
at least one of the two boolean expressions must be true |
not |
negates the boolean value |
Below is a truth table, where x
and y
represent Boolean values or
expressions. For example, x
could be age >= 18
and y
could be status ==
"Yes"
. Each row should be read as follows: for the given Boolean values of
x
and y
, what is the result of x and y
, x or y
, and not x
:
x | y | x and y | x or y | not x |
---|---|---|---|---|
True |
True |
True |
True |
False |
True |
False |
False |
True |
False |
False |
True |
False |
True |
True |
False |
False |
False |
False |
True |
De Morgan’s Laws
If you want to check if a Boolean expression C
is false, you can use not C
to evaluate to True
when C
is false. For more complex expressions using and
or or
, we can apply the following rules known as De Morgan’s laws.
not (A and B)
←→ (not A) or (not B)
not (A or B)
←→ (not A) and (not B)
Exercise: Logic Tests
For this exercise, use the program logicTests.py
to test your understanding of logical operators. You don’t need to write any code for this exercise, just run the program and follow the prompts.
$ python3 logicTests.py
Friday
Exercise: Water Phase
Write a program in phase.py
that, given a temperature in °C, prints the phase of water at that temp assuming standard pressure.
$ python3 phase.py Enter a temp in °C: 150 At 150C, water is a gas $ python3 phase.py Enter a temp in °C: 20 At 20C, water is a liquid $ python3 phase.py Enter a temp in °C: -10 At -10C, water is a solid
Comparing Strings
We can compare string values just as we can compare integer and float values. That is, we can use any relational operator on a pair of a strings.
"Aardvark" < "Baboon"
Strings in python3 are compared lexicographically, i.e., based on their sorted dictionary order. So, the above expression is True
because Aardvark
appears earlier in the dictionary than Baboon
.
Python actually compares the two strings character-by-character until it finds a difference. So, it will first compare A
to B
. It finds that they are different, and so it returns True. If the expression is:
"Apple" < "Applied"
Python first compares the A
s, then each p
, then the l
s , and finally stops at the next position since e
and i
are different. Since e
comes before i
in the alphabet, the expression returns True.
What if we had:
"apple" < "APPLE"
What does Python do here? Internally, everything in the computer is represented numerically in binary (0s and 1s). So, even text is really represented as a series of numbers (positive integers, specifically). The encoding, or conversion, is known as Unicode. We can find the conversion using the ord()
function. The ord()
functions takes a string or length one (a character) and returns an integer value.
The actual integer value is not important for you to know. One nice property of the ord() function is that the lowercase letters a through z return sequential values, as do the upper case letters
A through Z and the digits 0 through 9 . This can be helpful for manipulating individual letters/digits.
|
$ python3 >>> ord('C')-ord('A') 2
This indicates C
is two characters away from A
.
$ python3 >>> ord('p')-ord('a') 15 >>> ord('a')-ord('A') 32
So to answer our question above, comparing apple
to Apple
we need to compare the Unicode value of a
to A
. A
has a smaller Unicode value than a
, so the expression is False
.
We can also convert in the other direction - from a number to a character using the chr()
function. The chr()
takes a non-negative integer as input and returns a string of length one (a character). We typically use this in conjunction with ord()
to avoid working with the numbers directly, as the number have no intrinsic meaning.
>>> ord_a = ord('a') >>> type(ord_a) <class 'int'> >>> chr(ord_a+2) 'c' >>> chr(ord_a+10) 'k' >>> chr(ord_a+25) 'z' >>> chr(ord_a) 'a'
Exercise: lowercase
Can you think of a way to use ord()
and char()
to tell if a character is a lowercase letter?
$ python3 lowercase.py
Enter a character: a
a
is a lowercase letter
$ python3 lowercase.py
Enter a character: d
d
is a lowercase letter
$ python3 lowercase.py
Enter a character: D
D
is NOT a lowercase letter
$ python3 lowercase.py
Enter a character: $
$
is NOT a lowercase letter