Module 1: Conditionals

Unit 1 > Module 1


Objectives

 

By the end of this module you will be able to:

 

1.0 Audio:
 


1.0    A simple example

 

Consider this program:

x = 5
y = 4

if x > y:
    print('Hey, x is bigger')

print("OK, we're done")
    
 

1.1 Exercise: In my_ifexample.py, type up the above and examine the output. Then, just below the print with 'Hey' (and indented 4 spaces) add another print to print anything. Then, change the value of y to 6 and report the output in module1.pdf. Submit the program with these modifications.
 

Let's explain:

  • First, observe:

  • Now, at the moment the if-statement executes, the condition is evaluated:

    If the condition is true then the code that's indented below the if-statement executes.

  • Consider what happens when y is 6:

 

1.2 Exercise: Consider this program:

s = 0
for i in range(6):
    s = s + i

if s < 15:
    print('Less than 15')

print('Done')
  
Try to mentally execute (trace its execution in your mind) and predict the output before typing it up in my_ifexample2.py to confirm.
 


1.1    if-else

 

Think of else as if's occasional partner.

Consider this example:

x = 5
y = 4

if x > y:
    print('Hey, x is bigger')
else:
    print('Who said x is bigger?')
    print('In fact, y is bigger')

print("OK, we're done")
    
 

1.3 Exercise: Type up the above in my_ifexample3.py and examine the output. Then, change the value of y to 6. What is the output? Change y to 5. What is the output? Report these in your module pdf.
 

Let's point out:

  • When x is indeed larger than y, the code in the if-body executes:

  • When the if-condition evaluates to false:

  • What happens when x is 5 and y is 5?

 

Because some of these arrows might be difficult to follow, let's emphasize some blocks (lines) of code:

  • First consider when x is larger than y:

  • And when y is larger than x:

 


1.2    if-elif-else

 

Consider this variation:

x = 5
y = 5

if x > y:
    print('Hey, x is bigger')
elif y > x:
    print('Who said x is bigger?')
    print('In fact, y is bigger')
else:
    print('Actually, they are equal')

print("OK, we're done")
    
 

1.4 Exercise: Type up the above in my_ifexample4.py and examine the output. Then, try y=6 and y=4. Report results in your module pdf.
 

Let's explain:

  • First, consider the case x=5, y=5:

  • Now consider x=5, y=4:

  • Next: x=5, y=6:

 

One can have as many elif sections as one would like, for example:

x = 3

if x == 1:
    print('one')
elif x == 2:
    print('two')
elif x == 3:
    print('three')
elif x == 4:
    print('four')
else:
    print('big')
    
Think of the whole thing as a giant if-statement:

In the above case, when x is 3, the execution path through the giant if-statement is:

 

1.5 Exercise: Type up the above in my_ifexample5.py. Then, try each of x=1, x=2, x=4, x=5. Draw the execution pathways (similar to the picture above) for each case in your module pdf.
 

Consider this program:

x = 5
y = 4
z = 3

if x > y:
    print('Hey, x is bigger')

if x > z:
    print('x is bigger than z')
    print('So, x must be the largest')
  
 

1.6 Exercise: Type up the above in my_ifexample6.py. Try y = 6. Explain why it does not work. Then try to alter the program without changing the print-statements so that it works in all cases for possible values of x,y, and z. That is, whichever of the above print-statements gets printed correctly reflects the values of x, y and z.
 

1.7 Video:

 


1.3    Nested conditionals

 

Consider this program:

a = 3
b = 4
c = 5

if a < b:
    if a < c:
        print('a is the smallest')
    else:
        print('a is not the smallest')

print('Done')
    
This is an example of a nested conditional (nested if):
  • First, examine the indented structure:

  • The flow of execution:

 

Consider this variation:

a = 3
b = 4
c = 5

if a < b:
    if a < c:
        print('a is the smallest')
    else:
        print('a is not the smallest')
    print('We know a is less than b')
else:
    print('We know a is not less than b')

print('Done')
  
 

1.8 Exercise: Type up the above in my_nestedif.py. Draw the flow of execution for the following three cases: (1) when a=3, b=4, c=5; (2) when a=3, b=4, c=2; (3) when a=6, b=4, c=5.
 

1.9 Exercise: In my_smallest_of_three.py, modify the above program so that it prints out, appropriately, one of "a is the smallest", "b is the smallest" or "c is the smallest", depending on the actual values of a, b, and c. Try different values of these variables to make sure your program is working correctly.
 

1.10 Audio:
 

Note:

  • A numeric variable can be: strictly less, less than or equal to, strictly greater, greater than or equal to, or equal to another variable.

  • Accordingly, the different types of less/greater comparisons are:
         a < b      # Strictly less than, as when a=3, b=4
         a <= b     # Could be less (a=3, b=5), could be equal (a=3, b=3) 
         a > b      # Strictly greater (a=3, b=2)
         a >= b     # Could be greater (a=3, b=1), could be equal (a=2, b=2) 
      
 


1.4    Combining conditions

 

Consider this program:

x = 5
y = 5
z = 5

if x == y and y == z:
    print('All three are equal')
    
Note:
  • The first thing to point out is the == operator:
    • Because we've been using the equals operator for assigning values to variables, we need something else to test for equality.
    • The equality operator in Python is == as in:
      if x == y and y == z:
        
    • Alas, the problems with limited keyboard symbols!

  • Important: the difference between = and == is very important to remember. It's easy to make a mistake one forgets.

  • The if-statement combines two conditions:
    if x == y and y == z:
      

  • The combining occurs with the Boolean operator and:
    if x == y and y == z:
      

  • We can clarify the parts and combination thereof using parens:
    if (x == y) and (y == z):
      

  • The two parts are often called clauses:
    • First clause (x == y):
      if (x == y) and (y == z):
        
    • Second clause (y == z):
      if (x == y) and (y == z):
        
    • You could have many more clauses.

  • The "and" operator works like this:

  • Boolean is pronounced "BOO lee unn".

  • A Boolean operator takes expressions and computes to either true or false.
 

Let's go back to finding the smallest of three numbers using conditionals:

a = 3
b = 4
c = 5

# Fill in code here ... 
  
 

1.11 Exercise: In my_smallest_of_three2.py, fill in code to identify which of the three variables has the smallest value, depending on the actual values of a, b, and c. Use if-statements with multiple clauses. Try different values of these variables to make sure your program is working correctly.
 

1.12 Video:

 

As the counterpart to the and operator, there is the or operator:

a = -2.718

if (a <= 0) or (a >= 1):
    print('a is not between 0 and 1')
    
 

1.13 Exercise: Type up the above in my_boolean2.py. Then try a=0.5.
 

Note:

  • We have shown how to write "less than or equal to" using <=.

  • So, now we can add "equals" and "not equals" to the numeric comparisons:
         a < b      # Strictly less than, like a=3 < b=4
         a <= b     # Could be less, could be equal (a=3, b=3)
         a > b      # Strictly greater (a=3, b=2)
         a >= b     # Could be greater, could be equal 
         a == b     # Exactly equal
         a != b     # Not equal
      

  • For the or operator to evaluate to true, any one or both of the two expressions needs to be true.

  • Consider:
      a = 3
      b = 4
      if (a < 10) or (b < 10):
          print('One or both of them is less than 10')
      
    • In this case both will evaluate to true, and so the print statement executes.
    • Suppose we made a=3, b=11, the print statement will execute.
    • Suppose we change a=11, b=3, the print statement will execute.
    • But if a=11, b=12, the or fails (both clauses are false), and the print won't execute.

  • Incidentally, let's replace or with and in the above case, and see what we get:
      a = 3
      b = 4
      if (a < 10) and (b < 10):
          print('Both of them are less than 10')
      
    In this case, both sub-conditions are satisfied, and so the whole if-condition is satisfied, which means the print will execute.

  • But if we had
      a = 3
      b = 4
      if (a < 10) and (b > 10):
          print('Both of them are less than 10')
      
    In this case, the second comparison fails, and the print won't occur.

  • Whereas if we had or:
      a = 3
      b = 4
      if (a < 10) or (b > 10):
          print('One or both of them is less than 10')
      
    Here, it's enough that a is less than 3, and so the print executes even though "b greater than 10" fails.
 

Next, let's look at the NOT operator (written with !):

x = 5
y = 6
z = 7

if (x != y) and (x != z):
    print('x is different from y and from z')
    
Here, read != as "not equals".
 

1.14 Exercise: Type up the above in my_boolean3.py, then change z to be 6 (same as y). What do you observe?
 

One can combine any number of and's, for example:

x = 5
y = 6
z = 7

if (x != y) and (x != z) and (y != z):
    print('x, y, z are all different')
  
 

The difference between != and not:

  • We should read != as "not equals" just as we read == as "equals".

  • There is another operator called not, which applies to Boolean expressions, as we'll see next.
 

The not operator

  • One can apply the not operator to groups of clauses using additional parens:
    x = 8
    
    if not ( (x == 5) or (x == 6) ):
        print('x is neither 5 nor 6')
      

  • Here, not is asking that whatever it applies to be false.

  • Thus, consider the expression
    if not ( (x == 5) or (x == 6) ):
      

  • In this case, x is 8. So, neither of (x == 5) nor (x == 6) is true.

  • Thus, the whole expression ( (x == 5) or (x ==6) ) is false.

  • Which means not ( (x == 5) or (x ==6) ) evaluates to true.

  • Therefore, the print executes.
 

1.15 Exercise: Suppose integer variables a,b,c,d,e have values a=1, b=1, c=3, d=4, e=5. Consider the following three expressions:

	( (a <= b) and (c+d > e) and (d > 1) )

        ( (a > c) or ( (c+1 < e) and (c-b > a) ) )

        not ( (b == d-c) and (a > b) or (c < d) )
  
Try to evaluate each expression by hand. Then, in my_boolean4.py, write up each of these in an if-statement to see if the result matches with your hand-evaluation.
 

1.16 Exercise: In my_boolean5.py, write a program that begins with

a = -3
b = -4
  
and uses conditionals to print out the absolute difference between the two numbers. In the above case, the difference is 1. In the case of a=3, b=4, the difference is also 1. When a=-3, b=4, the difference is 7.
 

1.17 Video:

 


1.5    Conditionals and loops

 

Let's write a program to loop through integers and print only the even numbers:

n = 10
for i in range(1, n+1):
    if i % 2 == 0:
        print(i, 'is even')
    
 

1.18 Exercise: In your module pdf, trace through the iterations in the above program. Then, in my_oddeven.py, modify the above program so that for every number between n and 1, going backwards, the program prints whether it's even or odd, as in:

10 is even
9 is odd
8 is even
7 is odd
6 is even
5 is odd
4 is even
3 is odd
2 is even
1 is odd
  
 

1.19 Audio:
 


1.6    Conditionals and lists

 

Suppose we have a list of numbers, representing daily profits (sometimes negative, sometimes positive) and we only want to add up the positive numbers:

earnings = [-5, 2, 3, -9, 12, 4, -30]
total = 0
for k in earnings:
    if k >= 0:
        total += k

print('Total profit =', total)
    
 

1.20 Exercise: Trace through the values of total and k in your module pdf.
 

1.21 Exercise: Given a list like

A = [-5, 2, 4, -9, 12, 13, -30, -21, -20]
  
we see that 12,13 and -21,-20 are pairs of consecutive numbers. Write a program called my_consecutive.py, with loop and a conditional to identify such consecutive pairs and print them. For the above list, the output should be:
Consecutive pair found: 12 13
Consecutive pair found: -21 -20
  
 

1.22 Audio:
 

Next, let's write a program that asks the user to enter a number that we then check is in a list of numbers:

# The list of numbers:
A = [-5, 2, 4, -9, 12, 13, -30]

# Receive what the user types in (as a string):
user_str = input('Enter an integer: ')

# Convert string to integer:
k = int(user_str)

# Check whether in the list:
if k in A:
    print(k,'is in the list')
else:
    print(k,'is not in the list')
    
Note:
  • The in operator checks member in the list:
    if k in A:
      
 

1.23 Exercise: Suppose you are given two lists like

A = [-5, 2, 4, -9, 12, 13, -30, -21, -20]
B = [2, -9, 11, 16, 13]
  
Notice that some elements of A (like 2) also exist in B. In my_twolist.py, use the list membership idea to print those elements of A that are also in B. For the above example, the output should be:
2 in A also found in B
-9 in A also found in B
13 in A also found in B
  
 

1.24 Audio:
 


1.7    More examples with lists

 

Consider the following program that aims to find duplicates in a list:

A = [2, 9, 2, 6, 4, 3, 3, 2]
for k in A:
    if k in A:
        print('Duplicate found:', k)
    
In the list, we can see that 2 occurs thrice, and 3 occurs twice. Both should be listed as duplicates. Is this the case?
 

1.25 Exercise: Trace through the iterations in the above program and explain why it does not work.
 

Now consider this variation:

A = [2, 9, 2, 6, 4, 3, 3, 2]
for i in range(len(A)-1):
    for j in range(i+1, len(A)):
        if A[i] == A[j]:
            print('Duplicate found:', A[i])
    
 

1.26 Exercise: Trace through the iterations in the above program and explain the output. Why does the inner loop start with i+1?
 

1.27 Audio:
 


1.8    Some stats via programming

 

Let's now apply our practice with conditionals to solve some problems in probability and statistics.

For example: Suppose I toss a coin 4 times and observe the face that's up. What is the probability that I get all "tails" (not one toss shows "heads").

Let's do this in steps.

First, let's write a program to toss a coin 4 times

import random

coin = ['heads', 'tails']
for i in range(4):
    toss = random.choice(coin)
    print(toss)
    
 

1.28 Exercise: Type up the above in my_cointosses.py and run it a few times to see what you get.
 

Note:

  • We have made a list of strings:
    coin = ['heads', 'tails']
      

  • Python has a useful way to randomly select a member of a list:
        toss = random.choice(coin)
      

  • Alternatively, we could have written:
        toss = random.choice(['heads','tails'])
      
    and avoided defining coin.
 

Next, instead of printing the results, let's count the number of heads observed:

import random

count = 0
for i in range(4):
    toss = random.choice(['heads', 'tails'])
    if toss == 'heads':
        count = count + 1

print('Number of heads', count)
    
 

1.29 Exercise: Type up the above in my_cointosses2.py and run it a few times to see what you get.
 

Note:

  • Observe how the string that's randomly selected from the list is compared against 'heads':
        if toss == 'heads':
            count = count + 1
      
 

Next, what we need to do is repeat the 4-coin toss many times:

  • Suppose we call 4-coin tosses a single trial.

  • Clearly, if we ran a single trial and obtained 1 heads (count=1) then, could we conclude that the probability of getting all-4-tails is zero?

  • What we need to do is run a large number of trials and record in how many trials we get a run of 4-tails.

  • We'll use the term "success" to identify a trial in which we get all-4-tails.

  • Let's examine the code:
    import random
    
    trials = 10
    successes = 0
    for i in range(trials):
        # Count number of heads in 4 tosses:
        count = 0
        for i in range(4):
            toss = random.choice(['heads', 'tails'])
            if toss == 'heads':
                count = count + 1
    
        # If the count is zero, that's a success
        if count == 0:
            successes += 1
    
    # Ratio of successes to trials:
    probability = successes / trials
    print('probability =', probability)
        
 

1.30 Exercise: Type up the above in my_cointosses3.py and run it a few times to see what you get. Then increase the number of trials to 100000 and see. The theoretical answer is 0.0625 (approximately 6% chance there's no heads in 4 tosses).
 

1.31 Exercise: In my_cointosses4.py, write a program to run a large number of trials of the following experiment: toss a coin 10 times and record a success if you get an equal number of heads and tails.
 

1.32 Audio:
 

Now let's solve a problem with that other favorite manner of generating chance: dice

We'll roll two dice and add the numbers face up. We want to ask: what are the chances we get 7 (when added up)?

Here's the program:

import random

possible_outcomes = [1,2,3,4,5,6]
trials = 100000
successes = 0
for i in range(trials):
    roll1 = random.choice(possible_outcomes)
    roll2 = random.choice(possible_outcomes)
    if roll1 + roll2 == 7:
        successes += 1

probability = successes / trials
print('probability =', probability)
    
 

1.33 Exercise: Type up the above in my_dice.py and see what you get, reporting in your module pdf. Is there a number other than 7 for which the probability is higher?
 

Let's also look at how one can get Python to randomly generate real numbers, for example:

import random

trials = 100
total = 0

for i in range(trials):
    x = random.uniform(5, 10)
    print(x)
    total += x

print('mean =', total/trials)
    
Note:
  • By using
        x = random.uniform(5, 10)
      
    we can generate a random real number between 5 and 10.

  • In the above program we are generating many such numbers and calculating their average.
 

1.34 Exercise: Type up the above in my_uniform.py, then increase the number of trials, and see what you get as the average, reporting in your module pdf. What is the average when you generate numbers between 25 and 30 and how does that compare with the average of the numbers 25 and 30? Explain why this should make sense.
 

Before you head off to Vegas with your Python programs, let's point out:

  • You can use programming to explore ideas in probability and statistics, and solve real problems as well.

  • It is an exciting way to learn stats that we will have more to say about later.
 


1.9    Algorithmic art

 

Let's now use what we've learned to explore the notion of how computers can be programmed to generate abstract art.

In our first example, we'll draw lines from one border of a square to another:

Let's describe the main idea via some pseudocode:

  • In a loop we'll generate:
      Set up an initial x1,y1 and x2,y2
      for i in ...
          Pick a random color
          Draw a line from x1,y1, y2,y2
          Make the current endpoint the start of the next line:
          x1 = x2
          y1 = y2
          Pick a random border
          Now pick a new random point on the next border
      

  • When we pick a border, we'll need to figure out the coordinates.
 

1.35 Exercise: Download conditional_art.py and drawtool.py. Try it out and then examine the code to confirm that it follows the pseudocode. Try different values of n. Can you change the choices of randomly chosen colors to improve the result? Does it look good with just two colors? Next, starting with Kandinsky, find an example of abstract art that you think might be considered an analogue in the history of art. Include a screenshot of your improved art, and the historical painting in your module pdf.
 

Next, we'll explore an interesting question:

  • Think of random art at one end of a spectrum.

  • And highly-structured geometry at the other end, generated by an algorithm.

  • The question: can we adjust a "knob" that let's us generate a mix? And is that more aesthetic?
 

1.36 Exercise: Download conditional_art2.py. Try out different values (between 0 and 1) of the structure parameter, for example 0.9 and 0.1. Is there a value that provides an aesthetic mix? Try different n. Make changes to the code and submit a screenshot of the result.
 


1.10    When things go wrong

 

In each of the exercises below, first try to identify the error just by reading. Then type up the program to confirm, and after that, fix the error.
 

1.37 Exercise:

x = 5
y = 6
if x < y
    print('x is less than y')
      
Identify and fix the error in my_error1.py.
 

1.38 Exercise:

x = 5
y = 6
if x !< y:
    print('x is not less than y')
      
Identify and fix the error in my_error2.py.
 

1.39 Exercise: The following code intends to find the maximum number in a list:

A = [3, 1, 8, 4, 2, 5]

for k in A:
    largest = 0
    if k > largest:
        largest = k

print(largest)
      
Identify and fix the error in my_error3.py.
 

1.40 Exercise:

a = 2.5

# See whether a lies between 0 to 1, or 1 to 2, 
# or something else
if (a > 0) and (a < 1):
    print('between 0 and 1')
else if (a > 1) and (a < 2):
    print('between 1 and 2')
else:
    print('something else')
      
Identify and fix the error in my_error4.py.
 

1.41 Audio:
 



On to Module 2



© 2020, Rahul Simha