Class Notes Week 3


Announcements

Week 3 Topics

Monday Wednesday Friday


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:

  1. length. To get the length of a string, use the len command e.g. len("cs21") = 4
  2. indexing. Access a single character in a string using its position indexing from zero. For example, if name="Punxsutawney", then name[1] = "u".
  3. concatenation. Concatenate with the + operator. "hello" + "world" == "helloworld"

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 first name: **Tina**
Enter last name: **Fey**

Welcome Tina Fey

Task 2:
There are 7 characters in your name

Task 3:
Initials: T.F.

BONUS:
Last initials: a.y.

Task 4:
T
i
n
a

Topics for Quiz 1 stop here

String Accumulation

Picking up from last week, we'll look at examples of using the accumulator pattern but with the string data type. Suppose we want to create the string zzzzzzz with an arbitrary number n of z's.

We can follow the traditional accumulator pattern

  1. Initialize an accumulator variable
  2. Loop over some range
  3. Use accumulator

For strings, initialization is usually an empty string.

ans = ""

There is no space between two double quotation marks. Accumulation is done using the concatenation + operator. Our solution is:

ans = ""
n=7
for i in range(n):
  ans = ans+"z"
print(ans)

Boolean Logic

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. This will another computational tool we will use throughout the semester to design algorithms for problems.

The Boolean or bool type can only have two possible values True or False. Note in python3, both of these values begin with a upper case letter and the values do not have quotes around them. The value "True" 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.

Other relational operators:

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 python3 has a different semantic meaning. It is used for variable assignment and would store 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. You can check your answers in the python3 shell by typing python3 in the terminal.

x < 10
x >= 10
x != 15
x + 15 <= 20
x % 2 == 1

The % operator for number is the mod or remainder operator. x%y returns the remainder when x is divided by y using integer division. So if x//y=k and x%y=m then x=k*y+m for some integer k. What property does x have if x%2 == 1? What other values could x%2 possibly equal?

Branching with if

We will 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>

<condition> will be some statement that evaluates to a Boolean value. The code inside the statement <body> only runs if the condition is True. Here is a 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()

Notice the use of the : as we saw at the end of for loops, and also the indented <body> to indicate that this code is 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 form of the if/else is:

if <condition>:
  <body>
else:
  <else-body>

Again, if the <condition> is true, python will execute the code in <body>. However, if the condition is false, python executes the code in <else-body>. 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 our program above to print a different message if the temp is above freezing. Regardless of the temp, 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 indentation.

  if temp < 32:
    print("Freezing temperatures; be sure to wear a coat!")
  else:
    print("Spring is on its way!")
  print("Have a great day!")

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 larger decision block. Python will first evaluate <cond-1> and if it is 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 it is true, it will execute <body-2> and then skip over 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. If all the conditions are false, we execute the <else-body>, if it exists. 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.

Exercise: practice if statements

Practice if/else statements by writing a block of code that determines if a person's age makes them eligible to vote (18 or older on election day). A start of this program is available in cs21/inclasss/w03-boolean/voting.py if you run update21. Some potential output might look as follows:

$ python voting.py
Enter your age on election day: 20
You are eligible to vote

$ python voting.py
Enter your age on election day: 18
You are eligible to vote

$ python voting.py
Enter your age on election day: 2
You can't vote this year
You will need to wait 16 years

Exercise: Code tracing

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). Will these blocks give different results? Or are some of them equivalent in terms of what will be printed?

#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

Many times we want to ask compound questions, or have 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 have to be true
or at least one of the two boolean expressions has to be true
not negates the boolean value

Here is a truth table, where the 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

The precedence of operators is to evaluate in this order:

  1. Evaluate anything inside of ()
  2. Evaluate all relational operators
  3. Apply any not operators
  4. Evaluate and operators
  5. Evaluate or operators.
  6. If tied, evaluate left to right.

For example, if b=5 and c=10 we'd evaluate:

not True or b < 10 and c != 5

by first evaluating b<10 to True and c != 5 to True:

not True or True and True

Next, we apply not True to make it False:

False or True and True

Next, apply the True and True which is also True:

False or True

Lastly, we evaluate the or and the result is True.

Exercise: Logic Tests

For this exercise, use the the program logicTests.py to test your understanding of logical operators. You do not need to write any code for this exercise, just run the program and follow the prompts.

$ python3 logicTests.py

Exercise: Water Phase

Write a program in phase.py that given a temp 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 ints. That is, we can use any relational operator on a pair of a strings.

"Aardvark" < "Baboon"

Strings are compared lexicographically (i.e., based on their sorted dictionary order). So, the above expression is True because Aardvark appears earlier in the dictionary.

Drilling down, 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 As, then each p, then the ls, and finally stops at the next position since e and i are different. Since e comes first in the alphabet, it returns True.

What if we had:

"apple" < "APPLE"

What does Python do? To drill down even further, everything in the computer is represented 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:

$ python3
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> ord('A')
65
>>> ord('B')
66
>>> ord('Z')
90
>>> ord('!')
33

So to answer our question above, we need to compare the Unicode value of a to A. A is a small Unicode value, so the expression is False.

We can also convert in the other direction - from a number to a character using the chr() function:

>>> chr(58)
':'
>>> chr(100)
'd'
>>> chr(75)
'K'

Substrings, in operator

A substring of a string is a portion of the string that appears continguously. For example, "blue" is a substring of "blueberries". Python has some commands for accessing substrings.

The most relevant for us right now is the in operator. in takes a substring called the pattern and another string commonly called the target, and returns True if and only if pattern is a substring of the target string.

Sometimes, the pattern can be a single letter, but in general, the pattern can be any string.

>>> 'a' in "apples"
True
>>> 'b' in "apples" 
False
>>> "vark" in "Aardvark"
True
>>> "bbrries" in "blueberries"
False

String Formatting

The print statement is nice for outputting, but it is difficult to format the output in a way we prefer. For example, every time we put out a dollar amount, we can't guarantee two digits after the decimal point for the cents and we also have to always leave a space between the dollar sign and the amount. String formatting allows us to define string templates:

as well as optional width and precision values

An example, if we print out the float variable pi from the math library:

>>> from math import pi
>>> print(pi)
3.14159265359
>>> print("Pi is %f|" % (pi))
Pi is 3.141593|
>>> print("Pi is %.2f|" % (pi))
Pi is 3.14|
>>> print("Pi is %20.2f|" % (pi))
Pi is                 3.14|
>>> print("Pi is %-20.2f" % (pi))
Pi is 3.14                |