## Announcements

• Lab 2 available now.

• Quiz 1 Friday at start of class.

• Wednesday Ninja session good time to review.

## Monday

### 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.

#### Exercise: practice if statements

Practice `if/else` statements by writing a block of code (in `cs21/inclasss/w03/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:

```$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

#### 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: ```$ python3
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
>>> 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'```

## Friday

### Substrings, in operator

A substring of a string is a portion of the string that appears contiguously. 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 the pattern appears as a substring in the target.

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:

 %s string value %d int value %f float value

String formatting also enables optional width and precision values:

Feature Syntax Example Semantics

width

%<number>type

%10s

Format a number to a string with ten spaces minimum.

precision (float only )

%.<number>f

%.2f

Require exactly two digits after a decimal point.

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                |```

You can combine multiple templates in a single string format:

``````item = "dozen eggs"
qty = 4
price = 2.79
print("%d %s cost $%.2f" % (qty, item, qty*price) )`````` ### While Loops Another syntactic tool for designing programs in Python is the `while` loop. You’ve previously seen `for` loops, Boolean types, and `if` statements. The `while` loop is a mix of these three concepts. A typical `for` loop executes for a definite number of times. For example, programmers decide in advance to loop over things like finite lists, `range()` results, or the length of a string. What if we are expecting a user to enter input in a specific format (e.g., a positive integer, a valid date, or a string with no punctuation)? We could trust the user not to make a mistake, but this approach is not very robust. Instead, if we detect that a user made a mistake in typing input, we could prompt the user again. But how many times should we ask? Once? Twice? 100 times? With a `for` loop, you’d have to set the number in advance. A `while` loop can solve these types of computational problems by repeatedly looping until a Boolean condition is met. The general syntax of a `while` loop is: ```while <CONDITION>: <BODY>``` The <CONDITION> is a Boolean expression. When the condition evaluates to `True`, the body of the loop will execute and then re-evaluate the condition. When the condition finally evaluates to `False`, Python skips the body of the loop and executes the next line after the body. Note that a `for` loop can often be written as an equivalent `while` loop. Let’s look at some examples in `while_loops.py`. #### While Loop Exercise (challenging) Practice writing `while` loops, using conditional, and formatting strings in a program called `echo.py`. The program should repeatedly prompt the user for an input string. If the user types anything other than `quit`, you should print their message back with a counter of how many times you’ve "echoed" a message: ``````$ python3 echo.py
Enter a string: hello
Echo #1: hello
Enter a string: test string
Echo #2: test string
Enter a string: quit
program terminates``````

Use a `while` loop to continue asking the user for strings indefinitely until they type `quit`, and try using string formatting to print the `Echo # …​` lines.