## IT 116: Introduction to Scripting Class 9

### Reading Assignment

You should read Chapter 4, Repetition Structures, from our textbook, Starting Out with Python, before next week's class.

### Homework 4

I have posted homework 4 here.

It is due this coming Sunday at 11:59 PM.

### Mid-term

The mid-term exam will be given on Monday, July 2nd.

It will consist of questions like those on the quizzes along with questions asking you to write short segments of Python code.

60% of the points on this exam will consist of questions from the Ungraded Class Quizzes.

The last class before the exam, Thursday, June 28th, will be a review session.

You will only be responsible for the material in the Class Notes for that class on the exam.

The Mid-term is a closed book exam.

### Quiz 1

I have posted the answers to Quiz 1 here.

### Tips and Examples

#### Converting Results to Integer

• Students sometimes lose points on the homework assignments because they did not convert to integer correctly
• Converting to integer should be done by using the `round` function ...
• with only one argument
• Students have used two incorrect techniques to give integer results
• One way was to use the integer devision operator, //
• When using this operator, the decimal part of the result ...
• is thrown away ...
• giving a less precise answer
• Calculating the Celsius temperature that corresponds to 30 degrees Fahrenheit ...
• using normal division / ...
• gives us
```>>> fahrenheit = 30
>>>  (fahrenheit - 32) / 1.8
-1.1111111111111112```
• If instead of using / ...
• we use // ...
• we get
```>>> fahrenheit = 30
>>> (fahrenheit - 32) // 1.8
-2.0```
• which is way off
• Notice that even though we used // ...
• the result is a decimal
• When we do arithmetic on an integer and a float ...
• the result is always a float
```>>> 4 // 2.0
2.0
>>> 4.0 // 2
2.0```
• We only get an integer result ...
• if both operands are integers
```>>> 4 // 2
2
```
• The second improper way to convert to an integer ...
• was to use the `int` conversion function
• This function also throws away the decimal part ...
• of a number
• If we use `int` we get
```>>> celsius = -3
>>> int(celsius * 1.8 + 32)
26```
• If we use `round` we get
```>>>> round(celsius * 1.8 + 32)
27```
• Why the difference?
• Let's see what we get if we use neither function
```>>> celsius * 1.8 + 32
26.6```

#### Indent All Statements in a Code Block

• A code block is a group of Python statements ...
• that are executed under certain conditions
• Every `if` statement has at least one code block
• All the statement in a code block
• must be indented one tab over
• The last Class Exercise contained the following
```done = 'no'
total  = 0
while done != 'yes':
number = int(input('Please enter a number: '))
total  = total + number
done   = input('If you are finished, enter "yes" ')
print(total)```
• When I first gave this as a Class Exercise ...
• some students did not indent all of the code ...
• in the code block
• Their code looked like this
```total  = 0
while done != 'yes':
number = int(input('Please enter a number: '))
total  = total + number
done   = input('If you are finished, enter "yes" ')
print(total)```
• This code will loop forever ...
• because the statement which changes the value of done ...
• is outside the code block for the loop
• done never changes ...
• so the loop goes on forever

#### Use Spaces before and after =

• One of the simplest ways you can make your code more readable ...
• is to always put a space ...
• before and after every assignment operator
• Python won't care if you use spaces ...
• but your code will be easier to read
• Compare this lines
`name=input("Please enter your name: ")`
• with this
`name = input("Please enter your name: ")`
• Which would you rather read?

### Review

#### Logical Operators

• Each data type has its own set of operators
• Logical operators are operators ...
• that work on boolean values ...
• and produce boolean results
• The logical operators are
• and
• or
• not
• The `and` operator returns true if both its operands are true
```>>> 5 > 4 and 4 > 2
True```
• If either of its two operands are false, `and` returns false
```>>> 5 > 4 and 4 < 2
False```
• It also returns false if both its operands are false
```>>> 5 < 4 and 4 < 2
False```
• The `or` operator returns true if either of its operands are true
```>>> 5 > 4 or 4 < 2
True```
• It only returns false if both of its operands are false
```>>> 5 < 4 or 4 < 2
False```
• The `not` operator takes only one operand ...
• and reverses its value
• So true becomes false
```>>> not 5 > 4
False```
• and false becomes true
```>>> not 5 < 4
True```
• To show how the logical operators work ...
• we use truth tables
• Here is the truth table for `and`
p q p and q
true true true
true false false
false true false
false false false
• The truth table for `or`
p q p or q
true true true
true false true
false true true
false false false
• And the truth table for `not`
p `not` p
true false
false true

#### Short-Circuit Evaluation

• Let's say you had a boolean expression like this
`a > b  and c > d`
• If the first expression is false ...
• the result of the entire expression will be false ...
• regardless of the whether the last expression is true or false
• Similarly, if we have the expression
`a > b  or c > d`
• and the first expression is true ...
• the result of the whole expression will be true ...
• regardless of the whether the last expression is true or false
• It makes no sense for the interpreter to evaluate the last expression ...
• because it cannot change the result
• Whenever the value of the whole expression ...
• can be determined by the first expression ...
• the interpreter does not bother to evaluate the last expression
• This is called short-circuit evaluation
• Another term for this feature is lazy evaluation

#### Precedence of Logical Operators

• When we write an expression like
`a + b > c and c * d < a`
• there are three different kind of operators
• Arithmetic: +, *
• Relational: >, <
• Logical: and
• The order of precedence determines which operators a used before the others
• The logical operators, and, or and not
• Have lower precedence than arithmetic operators ...
• and lower than the relational operators
• The order of precedence is  ** Exponentiation *   /   //   % Multiplication, division and remainder +   - Addition and subtraction >   <   >=   <=   ==   != Relational Operators and   or   not Logical per Operators

#### Checking Numeric Ranges with Logical Operators

• One of the most input ideas in programming is something called data validation
• The basic idea is to check the data type and range of data ...
• before you use it in a program
• If a program needed to know a person's age ...
• in order to calculate retirement benefits ...
• The user should enter something like
`35`
• not
`thirty-five`
• since the later is a string, not a number
• Similarly if the user entered 12 or 200 for their age ...
• the program should realize the user made a mistake ...
• and ask again for the age
• In this case, we might want to make sure that the values ...
• were between 16 and 65
• When we need to determine whether a value is inside a range ...
• we use the `and` operator
```if age >= 16 and age <= 65:
print("The age entered is a reasonable value")```
• If we wanted to determine whether a value is outside a range ...
• we use the `or` operator
```if age < 16 or age > 65
print("Please enter your age again")```
• Actually Python allows us to write the same conditions ...
• in a much shorter way
• ```>>> age = 25
>>> if 16 <= age <= 65:
... 	print("Your age is in the right range")
... else:
...  	print("Your age is in the wrong range")
...
Your age is in the right range```
• The boolean expression
`16 <= age <= 65`
• is the same as writing
`16 <= age  and  age <= 65`
• In other words the `and` operator is implicit

#### Boolean Variables

• A variable is a name that represents a value in the computer's memory
• If the value it holds is `True` or `False` ...
• it is a boolean variable
• Boolean variables are often used as flags
• to indicate whether a certain condition in the program is true
• Flags can make a program much more readable
• For example if you were writing a program to compute the price of a ticket ...
• you might have the following logic in your program ...
• after reading in the age of the buyer
```if age < 10:
minor = True
else:
minor = False
if age > 65:
senior = True
else:
senior = False```
• You could then use these flags later in your program to calculate the ticket price
• Actually there is a shorter way to achieve the same results
```minor = age < 10
senior = age > 65```
• The expression on the right are both boolean expressions ...
• that result in the values of `True` or `False` when evaluated

#### Loops

• One of the most important structures in all of programming is a loop ...
• something our textbook calls a repetition structure
• A loop repeats a number of statements ...
• under certain conditions
• Whenever you need to do something over and over ...
• you will use a loop
• There are two types of loops
• Loops controlled by counting
• Loops controlled by some condition
• In loops that are controlled by counting ...
• the code keeps track of the number of times through the loop ...
• and stops when this loop count reaches a certain value
• In loops controlled by condition ...
• the code will keep looping as long as some condition is true

#### `while` Loops

• A `while` loop keep repeating ...
• as long as a certain condition is true
• It has the following format
```while BOOLEAN_EXPRESSION:
STATEMENT
STATEMENT
...```
• As long as the condition is true ...
• the statements in the code block will be run
• We use a `while` loop ...
• whenever we do not know how many times the loop should run
• The condition in a `while` loop ...
• is evaluated before entering the loop
• This means it is possible that the statements in the code block
• will never be executed
• The following code will total all number entered by a user ...
• and keep doing this until the user tells it to stop
```done = 'no'
total  = 0
while done != 'yes':
number = int(input('Please enter a number: '))
total  = total + number
done   = input('If you are finished, enter "yes" ')
print('Your total is', total)```
• When we rung this code we get
```\$ python3 total.py
Please enter a number: 34
If you are finished, enter "yes"
Please enter a number: 28
If you are finished, enter "yes"
Please enter a number: 39
If you are finished, enter "yes" yes
Your total is 101```

#### Testing Variables in While Loops

• If you look carefully at code above ...
• you will see that I gave the variable done a value ...
• before the loop ...
• even though this variable is set by the users ...
• when the script is run
• Why did I do this?
• Here's the same script ...
• with the line removed
```total  = 0
while done != 'yes':
number = int(input('Please enter a number: '))
total  = total + number
done   = input('If you are finished, enter "yes" ')
print('Your total is', total)```
• When I try to run this I get
```\$ python3 total_bad.py
Traceback (most recent call last):
File "total_bad.py", line 5, in <module>
while done != 'yes':
NameError: name 'done' is not defined```
• So done needs a value ...
• which can be anything ...
• except one particular value
• If we give done the value "yes" ...
• the loop will never run
• Here is another version of the code ...
• with done set to "yes"
```done = 'yes'
total  = 0
while done != 'yes':
number = int(input('Please enter a number: '))
total  = total + number
done   = input('If you are finished, enter "yes" ')
print('Your total is', total)```
• When I run this I get
```\$ python3 total_stupid.py
Your total is```

#### Infinite Loops

• When you write a `while` loop ...
• something must happen in the code block of the loop ...
• that will make the test condition become false ...
• or the loop will go on forever
• This is called an infinite loop
• When your code goes into an infinite loop ...
• you have to abort the program ...
• by hitting Control C

#### Data Validation Loops

• One common use of a `while` loop ...
• is to test values entered by the user ...
• to make sure it is the right data type ...
• and is in the right range of values
• Let's say we wanted the user to enter an integer greater than 0
• We would first ask the user for input ...
• then test whether the value entered is greater than 0
• If not, we would print an error message ...
• and ask for new input
• This is an example of an algorithm
• Which is a step-by-step description ...
• of how to perform a specific task
• A recipe is an example of an algorithm
• Here is one way of writing the algorithm above
```get value from user
while value is not greater than 0:
print error message
get a new value from the user```
• This is an example of pseudocode
• Pseudocode is an English language description of what the program will do ...
• written out like a computer program ...
• using `if` statements and loops

### New Material

#### Compound Statements

• The Python interpreter processes a script ...
• one statement at a time
• Many statements consist of a single line
• distiance = speed * time
• rate = .05
• print('Hello world!')
• A statement that can fit on a single line is called a simple statement
• Notice that I said it can fit on a single line
• A statement like this
```distance = speed_of_vehicle * time_traveled_today \
+ distance_of_starting_point```
• is spread out over two lines ...
• but it could be written on a single line
• Up until this point you only know two kinds of simple statements
• Assignment statemets
• Function calls
• In contrast, all control structures are compound statements
• Compound statements contain other statements inside them ...
• and cannot be written on a single line

#### The `for` Loop in Python

• The count controlled loop in Python ...
• is the `for` loop
• But it works differently from the `for` loop ...
• in other computer languages
• It worth taking a bit of time ...
• to see how `for` loops work in other languages

#### `for` Loops in Other Languages

• Every language that I have ever studied ...
• has had loop controlled by counting
• These loops always start with the keyword `for ...`
• followed by three statements or expressions
• These three entries operate on a loop variable ...
• which controls the loop
• The first entry gives the loop variable it's first value
• The next entry is a boolean expression ...
• that tests the loop variable
• The loop code will not run ...
• unless the loop variable passes the test
• The third entry changes the value of the loop variable
• The loop variable must change ...
• or the loop will go on forever
• Here is a small script that prints the numbers 1 to 10 ...
• using the scripting language Perl
```for (\$i = 1; \$i <= 10; \$i++) {
print "\$i\n";
}
```
• In Perl all variable names must begin with a \$ ...
• statements must end with a ; ...
• and code blocks must start with a { ...
• and end with a }
• The parentheses after the keyword `for` ...
• contain the three entries that control the loop
• The first entry gives the loop variable ...
• it's starting value
• The next entry is a boolean expression
• The loop code will not run ...
• unless this this expression is true
• The third item changes the value of the loop variable
• In this case it increases the value of the variable by 1
• This change happens after the last line in the code block is executed ...
• and before the second entry is tested again
• Here is a summary of the three entries
Entry Purpose When Run
`\$i = 1` Gives the loop variable its first value Once, before the code block is run for the first time
`\$i <= 10` Decides whether the code block is run Before running the statements in the code block
`i++` Changes the value of the loop variable After the last statement in the code block, but before running the loop test

#### `for` Loops

• The counted loop in Python is the `for` loop
• The `for` loop has the following format
```for VARIABLE_NAME in LIST_OF_VALUES:
STATEMENT
STATEMENT
...```
• This loop is similar in structure to the `while` loop
• It has a header line ...
• which controls how many times it loops
• Followed by an indented code block ...
• of statements that are executed ...
• with each pass through the loop
• Python's `for` loop works differently from `for` loops ...
• in other computer languages
• The `for` keyword is followed by a variable
• Next comes the `in` keyword ...
• followed by a list of values
• The first value in the list is assigned to the variable ...
• which keeps that value while passing through the code block
• When execution of the code block ends ...
• the next value in the list is assigned to the variable
• This continues until all values are used ...
• at which point the loop ends
• Here is a program that uses a `for` loop ...
• to print the value of 2 ...
• raised to the powers of 1 to 10
```\$ cat powers_of_2.py
# this program uses a for loop to print the powers of 2
# from 1 to 10

for number in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:
value = 2 ** number
print("2 to the power", number, "is", value)

\$ python3 powers_of_2.py
2 to the power 1 is 2
2 to the power 2 is 4
2 to the power 3 is 8
2 to the power 4 is 16
2 to the power 5 is 32
2 to the power 6 is 64
2 to the power 7 is 128
2 to the power 8 is 256
2 to the power 9 is 512
2 to the power 10 is 1024```
• You can do everything with a Python `for` loop ...
• that you can do with the `for` loop ...
• in other languages
• But the Python `for` loops makes some things easier
• In other languages the value of the loop variable ...
• must be an integer
• But not in Python
• The values of the loop variables can be a `float`
```\$ cat return.py
# prints the return on \$1000 for different rates of interest

principle = 1000
for rate in [.01, .02, .03, .04, .05, .06, .07, .08, .09, .1]:
new_value = principle * (1 + rate)
print("The return on \$1000 at " + format(rate, ".0%") + " is \$" + format(new_value, ",.0f"))

\$ python3 return.py
The return on \$1000 at 1% is \$1,010
The return on \$1000 at 2% is \$1,020
The return on \$1000 at 3% is \$1,030
The return on \$1000 at 4% is \$1,040
The return on \$1000 at 5% is \$1,050
The return on \$1000 at 6% is \$1,060
The return on \$1000 at 7% is \$1,070
The return on \$1000 at 8% is \$1,080
The return on \$1000 at 9% is \$1,090
The return on \$1000 at 10% is \$1,100```
• They can be strings
```\$ cat rainbow.py
# prints the colors of the rainbow

print("The colors of the rainbow are")
for color in ["Red", "Orange", "Yellow", "Green","Blue", "Indigo", "Violet"]:
print(color)

\$ python3 rainbow.py
The colors of the rainbow are
Red
Orange
Yellow
Green
Blue
Indigo
Violet```
• The values of the list variable can even be of different types
```\$ cat types.py
# prints the type of different values

for value in [1, 1.0, "one", True]:
print("The data type of", value, "is", type(value))

\$ python3 types.py
The data type of 1 is <class 'int'>
The data type of 1.0 is <class 'float'>
The data type of one is <class 'str'>
The data type of True is <class 'bool'>```

#### The `range` Function

• Creating the list of values is not hard if the list is short
• But what if we wanted to find the cubes ...
• of all the numbers from 1 to 100?
• Creating that list would be very tedious
• So Python provides the `range` function ...
• to make this easy
• The `range` function creates a special kind of list ...
• that consists of a sequence of integers
```>>> for number in range(10):
...   print(number)
...
0
1
2
3
4
5
6
7
8
9```
• Notice that the sequence of numbers started with 0 ...
• and ended with one less than the value of the argument
• There is a reason why the `range` function works this way ...
• but it won't make sense until you have learned more

#### Setting the First and Last Values with `range`

• What if we wanted to print the numbers from 1 to 10?
• The range function will do that ...
• if we give it two arguments ...
• instead of one
• When you call `range` with two arguments ...
• it will create a list of numbers ...
• that starts with the value of the first argument ...
• and ends with the value of the one less ...
• than the value of the second argument
• So if I wanted to print the numbers from 1 to 10 ...
• I would write
```>>> for number in range(1, 11):
...     print(number)
...
1
2
3
4
5
6
7
8
9
10```
• To get a particular sequence of values ...
• from the `range` function ...
• you give the starting value as the first argument ...
• and one more than the last value ...
• as the second argument
• So if I wanted to print the numbers from 11 to 20 ...
• I would write
```>>> for number in range(11, 21):
...     print(number)
...
11
12
13
14
15
16
17
18
19
20
```

#### Changing the Increment with `range`

• In the `for` loop in other languages ...
• the last entry tells the how much the loop variable change ...
• with each pass through the loop
• Usually the loop variable just gets incremented by 1 ...
• but you can use any integer value
• This is true of the `range` function as well
• If you call the `range` function with one or two arguments ...
• each value it creates is 1 more ...
• than the previous value
• But you can change this by giving `range` a third argument
• The third argument is called the step value
• It tells `range` how much each new value ...
• is to change ...
• from the previous value
• This means that I can print the even numbers ...
• by giving 2 as the third argument ...
• to `range`
```>>> for number in range(2, 11, 2):
...  print(number)
...
2
4
6
8
10```
• Similarly to count by three ...
• the third argument should be 3
```>>> for number in range(3, 22, 3):
...     print(number)
...
3
6
9
12
15
18
21```

#### Reversing the `range` Values

• So far, all the values we have created with `range` ...
• have always increased
• What if we wanted to go in the other direction?
• This can be done using the three argument version of `range`
• The third argument is the size of the step ...
• between one number and the next
• By default the step value is 1
• So to go in the other direction the step must be -1
• What arguments should we use ...
• if we wanted to print the numbers from 10 to 1?
• The first argument is the first number in the list
• But what should the value of the second argument be?
• Earlier I said that the value of the second argument ...
• should be 1 more than the last value
• Let's try 2 as the second argument
```>>> for number in range(10, 1, -1):
...     print(number)
...
10
9
8
7
6
5
4
3
2```
• Whoops
• In truth, the value of the second argument is more complicated
• The second argument should be what you get ...
• if you added the value of the step ...
• to the last number you wanted
• Here, we want the last number be 1 ...
• but the value of the step is -1
• so the second argument should be 0
```>>> for number in range(10, 0, -1):
...   print(number)
...
10
9
8
7
6
5
4
3
2
1```

#### Why Does Python Have the `range` function?

• Why does Python have the `range` function?
• If I wanted to write a script in Perl ...
• That listed all the even numbers from 2 to 10 ...
• I would write
```\$ cat perl_evens.pl
for (\$i=2; \$i <= 10; \$i+=2) {
print "\$i\n";
}

\$ perl perl_evens.pl
2
4
6
8
10```
• To do the same thing in Python ...
• I have to use the `range` function ...
• inside the `for` loop
```>>> for number in range(2, 11, 2):
...     print(number)
...
2
4
6
8
10```
• If you look closely you can see ...
• that the `range` function in Python ...
• provides loop variable values ...
• just like the 3 entries inside the parentheses ...
• in the Perl `for` loop
• This makes Python more complicated ...
• than Perl
• But Python values simplicity ...
• so what gives?
• By moving the responsibility for creating the loop variable values ...
• from the `for` loop ...
• into the `range` function ...
• Python makes the `for` loop more general
• It can do the same things `for` loops does ...
• in other languages
• But it will also work with lists ...
• and anything that looks like a list
• If I wanted to print the teams in the American League East ...
• in Python I would write
```\$ cat al_east_teams_1.py
# prints the teams in the American league

print("Here are the teams in the American League East")
for team in ["Boston Red Sox", "Baltimore Orioles", "Toronto Blue Jays", "Tampa Rays", "New York Yankees"]:
print(team)

\$ python3 al_east_teams_1.py
Here are the teams in the American League East
Boston Red Sox
Baltimore Orioles
Toronto Blue Jays
Tampa Rays
New York Yankees```

#### `for` Loop that Don't Use the Loop Value

• Whenever I need a `for` loop to do something ...
• a certain number of times ...
• I would use the `range` function ...
• to give me a list of numbers ...
• with that many values
• But I don't have to use the values ...
• inside the loop code block
• If I wanted to cheer the Red Sox 5 times ...
• I would write
```>>> for number in range(5):
...   print("Go Red Sox!")
...
Go Red Sox!
Go Red Sox!
Go Red Sox!
Go Red Sox!
Go Red Sox!```
• In this loop we did not use the value of number ...
• just the fact that the list that gave it values ...
• only had 5 entries