from IPython.core.display import HTML

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

Script 3

Recap from script 2

We learned:

  • rules for valid and invalid variable names
  • input and output with input and print functions
  • algebraic operations +, -, *, /, ** and //.
  • import math and how to use functions as math.sin and constants as math.pi
  • an introduction to types (a type determines the range of values of data as well as the defined operations, compare + for numbers and strings)
  • an introduction to strings
  • that the string "123" is not the same as the number 123.
  • that functions have arguments and return values
  • how nested function calls work
  • how to convert strings representing numbers to the actual numbers with int and float.

Logical values

Up to now we know the following types:

  • int to handle integer numbers
  • float to handle real numbers
  • str to handle text

In addition to these types Python offers the so called bool type for handling logical values True and False:

am_i_clever = True
print(am_i_clever)
print(type(am_i_clever))
True
<class 'bool'>
python_is_boring = False
print(python_is_boring)
print(type(python_is_boring))
False
<class 'bool'>

The range of bool type consist of only two values True and False. The exact writing with a capital letter in the beginning is important !

As "123" is different to the number 123 the string "True" is not the same as the logical value True.

Comparisons

Usually we create logical values when we compare data. For example if we ask if 3 is smaller than 4 we can express this as

print(3 < 4)
True

For comparison Python knows the following operators:

notation meaning
< is smaller
> is larger
<= is smaller or equal
>= is larger or equal
== is equal
!= is not equal

The exact writing again is important, =< or => are wrong !

Take care not to mistake = and ==: The first means "assign a value to a variable" which we noted in the first script. The second checks if two given values are equal.

Here are some examples:

print(4 < 3.0)
print(4 > 3.0)
print(3 <= 3.0)
print(3 >= 4.0)
print(3 == 4.0)
print(3 != 4.0)
False
True
True
False
False
True

Computing with logical values

Similar to algebraic operators as + for numbers we can compute with logical values with the operations and, or and not:

x = 3
print(x >= 4 and x <= 3)
False

Above first the comparisons x >= 4 and x <= 3 are evaluated to False resp. True. Finally False and True results in False.

print(x >= 4 or x <= 3)
True
print(not True)
False

Typical error

Example: you want to check if a value x is 0, 1 or 2. The correct way to write this is

print(x == 0 or x == 1 or x == 2)
False

Sometimes programming beginners write this expression as they pronounce it:

print(x == 0 or 1 or 2)
1

This does not trigger an error message but you can see that something is going wrong because the result is not a boolean value ! (The "wrong" notation has a meaning in Python, but explaining this is beyond this course).

Evaluation order

If you use logical computations the order of evaluation is

  1. Comparisons are evaluated first
  2. Then not
  3. Followed by and
  4. and finally or

You can use brackets to change this or to make some expressions more readable. So the following two expressions are equivalent:

print(3 < 4 or 4 > 5 and 5 > 3)
print((3 < 4 or (4 > 5 and 5 > 3)))
True
True

Comparing strings

If you compare strings, == and != will work as expected:

print("abcd" == "Abcd", "abc" != "abc ")
False True

But strings are ordered as well, we use so called "phone book ordering". This is a < b for strings means that you would find a before b in a phone book:

print("abc" < "abd", "abc" > "abcd")
True False

Control question

  1. Repeat the instructions and examples above.
  2. Try to forecast the values of the following expressions, then use Python to check if you are right.

    3 < 4 and 4 <= 5 and 5 != 6
    3 == 4 or 3 != 4 and 3 == 4
    (3 == 4 or 3 != 4) and (3 == 4)
    "ab" <= "bcd" or 3 == 4
    "ab" > "bcd" and 3 == 4
    "" == " "
    (3 = 3) or (3 != 4)

Branching with if

Branching allows execution of parts of the code depending on one or multiple conditions. We already introduced an example for if and else in the wage calculation example.

The simplest form of branching is a plain if:

x = 4
if x > 3:
    print("x is greater than 3")
print("x is", x)
x is greater than 3
x is 4

Program execution starts in the first line. So we set x to 4. Then the next line is executed: the Python interpreter checks if x > 3 is True. This is the case, so the indented line after if is executed: you can see this in the output below the code. Finally the last line prints a final message.

Again the spelling is important: the : at the end of the if statement is mandatory, the indentation of the following line too.

If we modify the first line and set x to 3 the condition x > 3 is False so the line after if will be skipped:

x = 3
if x > 3:
    print("x is greater than 3")
print("x is", x)
x is 3

Again: Program execution starts in the first line. So we set x to 3. Then the next line is executed: the Python interpreter checks if x > 3 is True. This is not the case, so the indented line after if is skipped. Finally the last line prints a final message.

The line after if x > 3: is called a code block. As we did see in the wage calculation example, such a block consists of one or more lines having the same indentation. Using the same indentation is important. You are free to choose one or more spaces, most Python programmers use four.

If we change the program a little, you can see that its behavior changes:

x = 3
if x > 3:
    print("x is greater than 3")
    print("x is", x)

The if condition is False so the subsequent indented code block (which now consists of two lines) is skipped. Then the interpreter reaches the end of the script and execution stops. This is why you see no output below the code !

Using inconsistent indentations within one code block is a syntax error. The Python interpreter raises an error message:

x = 3
if x > 3:
    print("x is greater than 3")
   print("x is", x)
  File "<ipython-input-17-ad8482bee7b9>", line 4
    print("x is", x)
                    ^
IndentationError: unindent does not match any outer indentation level

Branching continued: else

Sometimes we want to branch code execution handle two exclusive situations. This is where else is used:

x = 2
if x % 2 == 0:  # you still know what "%" computes ????
    print(x, "is even")
else:
    print(x, "is odd")
2 is even

You see two indented code blocks above: the first block after if x % 2 == 0: is only executed if the condition is True. If this is not the case the Python interpreter runs the code block after else:.

We change the value of x to 3 so you can see the different flow of execution in the output field:

x = 3
if x % 2 == 0:  # you still know what "%" computes ????
    print(x, "is even")
else:
    print(x, "is odd")
3 is odd

Again both code blocks may contain multiple lines and the indentation must be the same for every line within a block.

Exercise block 1:

  1. Repeat the examples above.
  2. Write a script which asks the user for an integer value and prints an appropriate message if this value is positive
  3. Extend this program so that an extra message is displayed if this is not the case.
  4. Write a script which checks if given float value is in the range 0.0 to 1.0 and displays an appropriate message.

Repetition exercise

Try to rewrite the wage computation script without cheating. (Remember: The user is asked for the number of hours he worked and for the wage per hour. Extra hours over 40 hours are honored by doubling the rate for the over hours. Finally the computed wage is displayed.).

Branching with elif for multiple checks

The last Python keyword for branched execution is elif. This is an abbreviation for "else if" and can be used as follows:

x = -2
if x > 1:
    print(x, "is a number greater than one")
elif x < 0:
    print(x, "is a negative number")
-2 is a negative number

Here the first condition x > 0 is False, so program execution continues at the elif statement. elif always is followed by another condition. Here x < 0 is True, so the following print is executed, what you can see in the output field.

If we change the script to x = 2 in the beginning we see that the first code block is processed, but not the second one:

x = 2
if x > 1:
    print(x, "is a number greater than one")
elif x < 0:
    print(x, "is a negative number")
2 is a number greater than one

If none of the conditions is True you see that both indented code blocks are skipped, execution continues after if-elif:

x = 0.5
if x > 1:
    print(x, "is a number greater than one")
elif x < 0:
    print(x, "is a negative number")
print("done")
done

elif statements may be repeated as often as needed. So we could extend the previous example as:

x = 0.5
if x > 1:
    print(x, "is a number greater than one")
elif x < 0:
    print(x, "is a negative number")
elif x >= 0 and x <= 1:
    print(x, "is in the range 0 to 1")
0.5 is in the range 0 to 1

In contrast to else, elif is always followed by a condition. We use if followed by multiple elif to test a sequence of conditions until the first condition evaluates to True.

if, elif and else combined

We can combine elif and else. If we look at the previous example the last elif will always be executed if both preceding conditions are False, we can simplify this to:

x = 0.5
if x > 1:
    print(x, "is a number greater than one")
elif x < 0:
    print(x, "is a negative number")
else:
    print(x, "is in the range 0 to 1")
0.5 is in the range 0 to 1

Syntax rules for chaining if, elif and else:

  • The if in the beginning is mandatory,
  • then zero or more elif statements follow
  • in the end we may have zero or one else branch.

This means:

  • elif after else is not allowed (and makes no sense)
  • multiple else make no sense and are not allowed.

Exercise block 2

  1. Repeat the code examples above, play with different values for x.
  2. Write a script which checks if a number is negative, positive or zero and writes an appropriate message for every case.
  3. Write a program which checks if a number is a multiple of 3 and/or 4 and writes appropriate messages for all four cases.

  4. Extend the wage computation with an extra rule: over hours over 60 hours are paid with the triple wage per hour !

  5. Lookup the exact rule for leap years (it is more than "multiple of 4" !), write a script which checks a given year whether it is a leap year or not.

Control question:

The following two snippets are syntactically slightly different. Can you explain the different output displayed when you run the code ?

x = 1

if x > 0:
    print(x, "is positive")
elif x < 0:
    print(x, "is negative")
else:
    print(x, "is zero")
1 is positive
x = 1

if x > 0:
    print(x, "is positive")
if x < 0:
    print(x, "is negative")
else:
    print(x, "is zero")
1 is positive
1 is zero

Preparation: Rock Paper Scissors

We will later implement the https://en.wikipedia.org/wiki/Rock-paper-scissors game and this exercise is a preparation for this.

https://en.wikipedia.org/wiki/Rock-paper-scissors has the following rules, we use abbreviations R, P and S for rock, paper, scissors:

  • if both players choose the same shape it is a tie
  • the winning combinations are: R beats S, S beats P, P beats R
  • all other combinations lose

Exercise 3

  1. Write a script which first asks the user for the move of player one then for the move of player two and then displays who wins. (Hint: you can implement the decision with one if followed by one elif and one else if you use and and or).

  2. Extend this so that invalid inputs are detected and handled after both inputs were provided.

Repetition exercise

Write a program which asks the user for an integer number $n$ and then computes and displays the product of the first $n$ natural numbers.

Nested code blocks

if-elif-else can be nested, here we have if and else within code blocks belonging to another if or else.

The line numbers below don't belong to the actual code, I added them to simplify following explanatins:

If the condition in line 3 below is true, the code block in lines 4 to 7 is executed, lines 9 to 13 are ignored.

If the condition in line 3 below is false, lines 4 to 7 are ignored, and program execution contineus at line 9:

n = int(input("gimme a number: "))

if n % 4 == 0:
    if n % 3 == 0:
        print(n, "can be divided by 4 and by 3")
    else:
        print(n, "can be divided by 4 but not by 3")
else:
    if n % 3 == 0:
        print(n, "can be divided by 3 but not by 4")
    else:
        print(n, "can neither be divided by 3 nor by 4")   
---------------------------------------------------------------------------
StdinNotImplementedError                  Traceback (most recent call last)
<ipython-input-27-6ae22978fe76> in <module>()
----> 1 n = int(input("gimme a number: "))
      2 
      3 if n % 4 == 0:
      4     if n % 3 == 0:
      5         print(n, "can be divided by 4 and by 3")

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

Exercise 4

  • type the program, test it with inputs 12, 8, 9 and 7 and try to follow program execution to understand how it works
  • rewrite the program using if and elif and else without nested if statements (this means that your code uses only 0 and 4 spaces for identation and not more).