from IPython.core.display import HTML

HTML(open("custom.html", "r").read())

Script 4

Recap from script 3

We learned about:

  • logical values True and False of type bool and how to combine them with operations and, or and not
  • comparisons ==, !=, <, >, <= and >= which produce logical values
  • several ways of branching with if, elif and else.

About +=

Increasing a given value like sum = sum + i is a common task in programming. Thus Python offers the abbreviation sum += i.

a = 7
a += 3
print(a)
10

We will use both versions in the script, sometimes sum = sum + ... is more readable.

Looping with for

Looping means that we instruct the Python interpreter to repeat execution of a given code block multiple times. We had a simple example in the first script when we introduced how to compute the sum of the first n natural numbers:

n = 3

acc = 0
i = 0
for x in range(n):
    i += 1
    acc = acc + i
    
print("the sum of the first", n, "natural numbers is", acc)
the sum of the first 3 natural numbers is 6

The statement for x in range(Y): instructs the Python interpreter to execute the succeeding code block Y times. We name this code block the body of the (for) loop.

for x in range(3):
    print("hi")
hi
hi
hi

The variable x we use above is the so called loop counting variable. You can choose other valid variable names instead of x. The key point is that this variable changes for every iteration. During the first execution of the body this variable has the value 0, during the second iteration it has value 1 and so on:

for i in range(4):
    print("i is", i)
i is 0
i is 1
i is 2
i is 3

So in general range(n) iterates over values 0 to n - 1.

Knowing this we can simplify our script from above:

n = 3
acc = 0

for j in range(n):
    acc = acc + j + 1
    print("j is", j, "acc is", acc)
    
print("the sum of the first", n, "natural numbers is", acc)
j is 0 acc is 1
j is 1 acc is 3
j is 2 acc is 6
the sum of the first 3 natural numbers is 6

Again it is important that the number of spaces used for indentation is the same for all lines in the code block !

Check question

Why do we use j + 1 above and just j ??

The range function can be used with two arguments as range(m, n). Here iteration starts with m and counts up to n - 1. So the upper limit is exclusive (we will see this in other places again):

Python rule to keep in mind:

Counting in Python starts with 0, upper limits are exclusive.

(I' only aware of one exception for the "upper limits are exclusive" rule which I will mention below)

n = 3
acc = 0

for j in range(1, n + 1):
    acc += j 
    print("j is", j, "acc is", acc)
    
print("the sum of the first", n, "natural numbers is", acc)
j is 1 acc is 1
j is 2 acc is 3
j is 3 acc is 6
the sum of the first 3 natural numbers is 6

Check Question

What does the following code compute ? Try to forecast the result using pen and paper, then use Python to check your result. The code has no practical application and just serves to check if you read the foregoing explanations carefully enough:

n = 2
k = 0
for i in range(3):
    n = n * n
    k = k + n + i
for i in range(3, 4):
    n = n - i
print(n, k)

Hint: if your prediction is not correct, it helps to insert print statements as follows, matching the output to the print statements assists in understanding the code:

n = 2
k = 0
for i in range(3):
    n = n * n
    k = k + n + i
    print("i=", i, "n=", n, "k=", k)  # this line is new

print()                               # this line is new
print("n=", n, "k=", k)               # this line is new
print()                               # this line is new
for i in range(3, 4):
    n = n - i
    print("i=", i, "n=", n)           # this line is new

print(n, k)

The plain print() statements create empty lines which increases the readability of the output.

Exercise block 1

  1. Reread the explanations above, type and run the code examples.
  2. Modify the previous script so that the sum of the first n square numbers 1 + 4 + 9 + .. is computed.
  3. Modify the previous script so that the product of the first n natural numbers is computed.
  4. Can you compute 1 + 2 + 4 + 8 + 16 + .. + 1024 using a for loop ? (The correct answer is 2047)
  5. Do you remember what happens if we multiply a number with a string ? We introduced this in solution proposals for script 03. Use for loops to produce the following figure:

    *    
    **   
    ***  
    **** 
    *****
  6. Display the following triangle with for and print. (string addition is your friend):

       *   
      ***  
     ***** 
    *******
  7. Extend both so the user can provide the height of the triangles.

Looping and branching combined

Up to now the body of a loop of a branch consisted of one block showing the same indentation. But we can extend this when we loop over a code block which in turn has a branched flow of execution.

For example we can extend our example above to compute the sum of the odd numbers among the first n natural numbers:

n = 5

odd_numbers_added = 0

for i in range(1, n + 1):
    if i % 2 != 0:
        # division remainder != 0 means not a multiple of two 
        odd_numbers_added = odd_numbers_added + i
        
print(odd_numbers_added)
9

Explanations:

The body of the for statement above consists of the two succeeding lines, the if statement has a body of one line.

  • in the first iteration i is 1, so the if condition is True, so odd_numbers_added is set to 1. We reach the end of the body of for so execution continues with for.
  • in the second iteration i is 2, so the if condition is False, so the block of if is skipped. This finished the body of the for statement, so we continue iterating.
  • in the third iteration i is 3, so the if condition is True, so odd_numbers_added is set to 3.
  • ...

Outlook:

The last example demonstrated how we can nest and combine the statements we learned up to now. Code blocks may have an arbitrary number of lines and we may nest loop and branching statements as deep as required.

About code blocks

Statements as for, if, elif and else are followed by a code block comprising one or more lines. Such a code block may contain other nested code blocks marked by an increased indentation of the lines. To detect the span of such a more complex code block the following two rules are very helpful:

  • the indentation of first line of a code block is crucial, (usually we use multiples of four spaces)
  • as soon as the indentation of a line is lower than the initial indentation ...
  • ... or if we reach the end of a script the code block ends.

Example:

for i in range(1, n + 1):
    if i % 2 != 0:
        # division remainder != 0 means not a multiple of two
        odd_numbers_added = odd_numbers_added + i
print(odd_numbers_added)

Here the first line of the code block after for is indented by four spaces, the second and third line by 8 spaces. Then zero spaces. So the code block ends before the print and comprises the three lines

if i % 2 != 0:
    # division remainder != 0 means not a multiple of two
    odd_numbers_added = odd_numbers_added + i

The same procedure determines that the code block after if has two lines:

# division remainder != 0 means not a multiple of two
odd_numbers_added = odd_numbers_added + i

Check question

Determine the extent of the code block after for in the following snippet by applying the rules we introduced above.

s = 1
for xxx in range(6):
    if xxx > 4:
        s = s * xxx
    elif xxx > 3:
        s = s - xxx
    else:
        s += xxx
print(s)

What does the code compute ? Try to forecast the result using pen and paper, then use Python to check your result. Insert print statements to understand the code if your result is not correct.

Comment: the code has no practical application and just serves to check if you read the foregoing explanations above carefully enough.

Exercise block 2

Some more difficult exercises in the script are marked as "optional", solving them is not required, but try to work on them if you have time to spare.

  1. Reread the explanations above, type and run the code.
  2. Modify the first example it to sum up the even numbers among the first n natural numbers
  3. Extend it to compute the sum of the even as well as the sum of the odd numbers among the first n natural numbers. Write a separate script for each of the following strategies:
    1. you compute both counts in sequence, so you have two loops in your script,
    2. you extend the if with an else in the body of a single for loop.
  4. Write a program which prints numbers 1 to 10 indicating whether the respective number is even. The expected output should be similar to

    1 is odd
    2 is even
    3 is odd
    ...
  5. Write a Python program which produces the first 30 iterations of https://en.wikipedia.org/wiki/Fizz_buzz#Play Hint: you may need one if followed by two elifs and one final else statement for this.

  6. Find all numbers in the range 1500 to 2000 (both limits included) which are multiples of $7$ and $13$.

  7. (optional): What do the following program compute for a given number n? Run it for n having values 2 to 19 and record the output. You should see a pattern. Do you understand now how this program works ?
n = 4
nip = True
for i in range(2, n):
    if n % i == 0:
        nip = False
print(nip)
False

More about strings: accessing characters in a string

As in for loops, Python starts counting with 0 in many places. For example the expression "abcd"[0] computes the 0th character of the string "abc" which is a:

print("abc"[0])
print("abc"[1])
a
b

The string and the index in brackets can be variables:

txt = "abcde"
for i in range(len(txt)):
    print("the", i, "th letter is", txt[i])
the 0 th letter is a
the 1 th letter is b
the 2 th letter is c
the 3 th letter is d
the 4 th letter is e

Exercise block 3

  1. Type the examples above, play with them and try to understand them. What happens if the index is the same as the length of the string or larger, what do you get for indices -1, and -2 ?

  2. Write a program which asks the user for a valid nucleotide sequence and prints all positions (starting with zero) of G symbols. You need for for this. The output for input GCCGGA should look like

    found G at position 0
    found G at position 3
    found G at position 4
  3. Write a program which takes a string and counts the number of As. Hint: iterate over all characters in the string and every time you see a A increment a counting variable.

  4. Extend this to compute the relative GC content of a given DNA sequence.

  5. Write a program which reverses a given string. So "abcde" is transformed to "edcba". Idea: start with an empty string "" and then use + to prepend the input string character by character.

And Now for Something Completely Different: Some Python facts

Some reading tips:

Looping with while.

Python has an alternative way to loop. In contrast to a for loop which executes a block of code for a given number of iterations, the while loop repeats a code block as long as a given condition is True.

i = 0
while i < 3:
    print("Rule number", i + 1, ": Python is awesome")
    i += 1
Rule number 1 : Python is awesome
Rule number 2 : Python is awesome
Rule number 3 : Python is awesome

As you can see the while keyword is followed by a logical expression and the line is again terminated with an :. The flow of execution is as follows:

  • check if condition is True.
  • if this is the case execute the block
  • jump back to while, check the condition again
  • if this is the case execute the block
  • ...
  • if the condition is False the code block after while is skipped and the interpreter processes the lines after this block.

Attention

  • the condition after while IS ONLY CHECKED AT THE BEGINNING OF EVERY ITERATION.
  • so if the condition becomes False during execution of the code block the computer will still complete the remaining lines in the code block.
  • if the condition is False from the beginning the code block is not executed at all !

You can rewrite all programs we had up to now from using for to using while. But you have to take care to increase the loop counting variable on your own, whereas for does this automatically.

The next example is a simple transformation of an example above where we computed the sum using a for loop. Compare both !

n = 3
i = 0
acc = 0

while i < n:
    i += 1
    acc = acc + i
    
print("the sum of the first", n, "natural numbers is", acc)
the sum of the first 3 natural numbers is 6

Check question

What does the following code snippet display ? Try to forecast the result using pen and paper, then use Python to check your result. If your prediction is not correct insert print statements to find the reason:

s = 0
i = 1
while s < 16:
    s += i
    i = 2 * i
print(s, i)

while s >= 16:
    s = 15
    print(s)
    i = i / 2
    s = i + 1

Exercise block 4

  1. Reread the explanations above, type and run the code.
  2. What is the difference if you would write if i < n: instead of while i < n: above?
  3. Rewrite the solutions from exercises 4 from block 1 and exercise 3 from block 2 with while instead of for.

Using break to stop looping

If you use the statement break within the body of a loop (no matter whether this is a for or a while loop), the execution of the body will end immediately and the program execution continues after the body. A very simple example is:

for a in range(3):
    print("a is", a)
    break
    print("this message will never be displayed")
print("after the for loop")
a is 0
after the for loop

Or:

a = 11
while a < 1000:
    print("a is", a)
    break
    print("this message will never be displayed")
print("after the while loop")
a is 11
after the while loop

These examples are quite artificial, in most cases we use break to break out from an infinite loop as follows:

summed = 0
while True:
    number = input("please input a number, use 'x' or 'X' to finish: ")
    if number == 'x' or number == 'X':
        break
    summed = summed + float(number)
print("the sum of the numbers you entered is", summed)
---------------------------------------------------------------------------
StdinNotImplementedError                  Traceback (most recent call last)
<ipython-input-16-d57d0b875686> in <module>()
      1 summed = 0
      2 while True:
----> 3     number = input("please input a number, use 'x' or 'X' to finish: ")
      4     if number == 'x' or number == 'X':
      5         break

/Users/uweschmitt/Projects/python3-course/venv/lib/python3.6/site-packages/ipykernel/kernelbase.py in raw_input(self, prompt)
    687         if not self._allow_stdin:
    688             raise StdinNotImplementedError(
--> 689                 "raw_input was called, but this frontend does not support input requests."
    690             )
    691         return self._input_request(str(prompt),

StdinNotImplementedError: raw_input was called, but this frontend does not support input requests.

Explanations:

while is always followed by a logical value. Usually we compute this logical value, e.g. as a < 1000 as we did above. If we provide the constant logical value True the loop will be executed forever.

The only way to leave this infinite loop is by using break as we did it above. You can see that this break also works if it is nested within the while loop.

Check question

What does the following code compute ? Try to forecast the result using pen and paper, then use Python to check your result. As always additional print statements will help you to understand the code in case your prediction is not correct:

i = 1
s = 1
while i >= 0:
    s = s + i
    if s == 3:
        break
print(i, s)

Extra question: where does the code block after while start, where does it end ?

Exercise block 5

  1. Type and run the examples above and try to understand them !
  2. Extend the program so that additionally the numbers provided by the user are counted and the count is displayed in the end. Further compute and display the average of the numbers. Extend your program to also handle the case when the user immediately enters X.
  3. This is the so called "$3n + 1$" (or collatz) iteration:

    1. We start with a number $n$
    2. Replace $n$ by $\frac{n}{2}$ if $n$ is even, else replace $n$ by $3n + 1$
    3. Repeat step B until $n == 1$

    So if we start with 17 this procedure computes values 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1.

    Implement this procedure: ask the user for a starting value $n$ and print the intermediate values of n.

    Note: The still unproven Collatz conjecture states that this procedure stops for every starting value $n$.

  4. Extend your implementation to count the number of iterations needed to reach $1$.
  5. Implement the algorithm for computing the greatest common divisor of two numbers which we introduced in the first script.

  6. (optional) Rewrite the solution of 2. without using break. For this you have to change the while True: statement to while number != 'x' and number != 'X':, and you have to use input twice: first before the while and second within the body of the loop.

  7. (optional) Now extend it so that additionally the maximum of the provided numbers is determined and displayed in the end. Strategy: Use a variable max_so_far to track the "maximum of the numbers seen so far". The trick is to find an appropriate starting value.

  8. (optional) Alternative solution to 7.: Initialize max_so_far with the first given number. Then update this variable after every user input if the given number is larger than the "maximum seen so far".

  9. (optional) Which starting value $n$ up to 100 produces the longest collatz sequence ? Don't determine this manually. Hint: you need two variables to track the "longest sequence seen so far" when iterating over the start values in range $1 ... 100$. On variable tracks the length of the "best" sequence, the other one the corresponding starting value.

Game 1: Number guessing game

The two final exercises of this script are to implement two games.

  1. The computer creates a secret random number in the range 1 to 100
  2. The user has to guess it. After every guess from the user the computer tells if the given number is to low, to high or correct. If the guess is correct the game ends, else this step is repeated.

Exercise 6

  1. use pen and paper to write some "pseudo Python code" which plays the number guessing game. Check this by "executing" the pseudo code with pen and paper !

The only missing piece to implement this game is to compute a random number. Python ships with the random module, this is how we use this:

import random
for i in range(5):
    print(random.randint(3, 7))  # random number in range 3..7
3
4
6
3
4

random.randint is the only exception I'm aware of where the upper limit is inclusive.

Else:

Counting in Python starts with 0, upper limits are exclusive.

Exercise block 7

  1. Run the last example a few times and see how the output changes.
  2. Implement the number guessing game in Python (to facilitate the development process display the secret number when generated). Hint: do not forget to use type conversion of the user input.
  3. Extend this program to count the number of guesses needed by the user
  4. If your program uses two input function calls reduce to on call this by using an infinite while loop.
  5. Extend your program to play multiple games: after a finished game the computer asks the user to play another game and a new game is started depending on the input. (tip: use an infinite loop around the existing code)
  6. Use random numbers to create a string with random characters A, T, G and C of length 10. You need either if-elif-else or clever string indexing to transform random numbers from 0 to 3 in to the corresponding characters. Start with an empty string and add character by character.

Repetition exercise

You remember the procedure for doing the repetition exercises as described at the end of script 01 ?

  • Write a program which checks if a given number is prime.
  • Write a program which reverts a given string

Game 2: Rock Paper Scissors

We already introduced https://en.wikipedia.org/wiki/Rock-paper-scissors in the previous script. Please repeat this before you go on.

The overall strategy to implement the game is:

  • We ask the user to enter R, S or P.
  • Then the computer chooses randomly a number 0, 1, 2 which we transform to R, S or P. You can generate the numbers using random.randint(0, 2) as we introduced for the number guessing game and then transform the number to the according symbol.
  • Then we compute the outcome of the game and display the result.

Exercise block 8

  1. Implement one iteration the game: ask the user, create an random computer move and display the outcome.
  2. Write Python code which uses an infinite while loop to ask the user until he enters one of R, S or P. In case of invalid input print a message before you ask again. Combine this with the solution from the previous step and test it.
  3. Allow the user to play as many games as wanted: In addition to R, S and P allow the user to enter X to stop playing.
  4. Extend the previous exercise to count the number of ties, player wins and computer wins and display a final message indicating these numbers and the final winner of the game.