Logic

  • Computers are machines that perform logic.
  • There are three fundamental logic functions
    • and
    • or
    • not
  • Logic functions take True and False as input
  • Logic functions return one of True or False as output.
  • They are defined by truth tables
  • Truth tables show the the output of a logic function for every combination of inputs.
Here is the truth table for and:
Input Ouptut
A B C
False False False
False True False
True False False
True True True
Here is the truth table for or:
Input Ouptut
A B C
False False False
False True True
True False True
True True True
Here is the truth table for not:
Input Ouptut
A B
False True
True False

There's one other important logic function that's worth mentioning:

Here is the truth table for xor:
Input Ouptut
A B C
False False False
False True True
True False True
True True False
  • Most of the time in English “or” means xor
    • Would you like soup or salad?
    • Coke or Pepsi?
  • The logic function have special syntax in Python (and most programming languages).
  • Here's an example that shows the truth table for and
>>> False and False
False
>>> False and True 
False
>>> True and False 
False
>>> True and True 
True
  • and is a binary operator
    • One value belongs on the left
    • The other value belongs on the right
  • not is a unary operator
    • The logic value appears on the right of not
>>> not True
False
>>> not False
True
  • Logic operators are often combined
  • We've seen numerical operations that test for values
    • == Equals
    • < Less than
    • <= Less than or equal to
    • > Greater than
    • >= Greater than or equal to
    • != Not equal to
  • Since the above operators produce either True or False you can combine them using logic operators.

What if you want to test if a number is between 1 and 100? Here's an example:

>>> number = 31 
>>> number > 1 and number < 100 
True
>>> number = 200 
>>> number > 1 and number < 100                                                                                      
False
  • Look closely at the syntax!
    • The variable number appears twice.
    • It's common for students to try to do this:
      • 1 > number < 100 THIS IS AN ERROR!

Making Decisions

  • Logic is the best way to make decisions in life.
  • It's the only way computers make decisions.
  • First a review of how Python uses spaces
  • When statements are indented they are inside a compound statement
  • The first statement that is left justified is outside of a compound statment.

  • The if statement conditionally runs instructions inside the body of the if statement.
  • The code is only run if the condition evaluates to True

Here's an example:

if number < 5 : 
    print ('The number is less than 5')

The code tests if the value of the variable is less than 5. If so the print statement is executed.

Here's a more complex example that uses a logic statement:

if number > 5 and number < 10 : 
    print ('The number is between 5 and 10')
  • You can have any number of statements inside an if statement.
  • Even other if statements.
if number < 5 : 
    print ('That number is too small.')
    number = input('Enter another number: ')
    if number >= 5 : 
        print ("That's better!")

If and Else

  • Sometimes you want to do something if the conditional is False
  • The else statement let's you do that.
  • The else statement must always follow an if

Here's a diagram of the structure of an if/else pair.

Here's an example:

if number > 5 and number < 10 : 
    print ('The number is between 5 and 10')
else:
    print ('The number is not between 5 and 10')
  • In the code above the one of the print statements will always be run
  • Which one depends on the value of number

Here's another example:

name = input("What's your name? ")
if name == 'Mike' : 
    print ("That's my name too!")
else:
    print ("Nice to meet you,", name)

And here's another example:

if grade >= 70 : 
    print ('Pass')
else:
    print ('Fail')

If/Elif/Else The Ladder

  • There's one more important form of logical statement in Python (and all programming languages)
  • The elif statement lets you make multiple decisions.

Here's an example of a statement that computes a letter grade:

if grade < 70 : 
    # Here the grade must be less than 70
    print ('F')
elif grade < 80 : 
    # The grade is greater than or equal to 70 and less than 80
    print ('C')
elif grade < 90 : 
    # The grade is greater than or equal to 80 and less than 90
    print ('B')
else: 
    # All other options eliminated, the grade is greater than or equal to 90
    print ('A')
  • The most important thing to understand is that only one alternative may every execute.
  • As program flow travels down alternatives are eliminated.
  • Subsequent elif statements must further reduce options.
  • The final else is optional.

Here's code that does exactly the same as the grade code above but does it in a different order:

if grade >= 90 : 
    print ('A')
elif grade >= 80 :
    print ('B')
elif grade >= 70 : 
    print ('C')
else :
    print ('F')

Pitfall!

It's essential that if/elif/else ladders always eliminate alternatives on the way down. If not the code will not work properly. This is an example of a common error:

if grade >= 90 : 
    print ('A')
elif grade >= 70 : 
    # Error! A grade of 85 would match here!
    print ('C')
elif grade >= 80 :
    # Error! This code will never run!
    print ('B')
else :
    print ('F')

Handling Errors: try, except, finally and raise

  • We've used the try/except structure to catch errors
  • Errors are raised when something goes wrong in a program.
  • Python itself can raise an error when there's a problem in your program
  • You can raise errors too.

Here's a simple example that catches any error:

try: 
    foo = int('Hello') # Always an error
except:
    print ('There was an error!')

You can't make an integer out of 'Hello' so there's an error. But what error?

  • The except in the form above catches any error that's raised at it.
  • But it doesn't let you know what the error is.
  • If you want to see the error you have to name it.
try: 
    foo = int('Hello') # Always an error
except Exception as e:
    print ('The error was:', e)

When you execute this code you see this output:

The error was: invalid literal for int() with base 10: 'Hello'
  • The error has been stored in the variable e.
  • The type of the variable is Exception
    • Or is it?
try: 
    foo = int('Hello') # Always an error
except Exception as e:
    print ('The error was:', e)
    print ('The type of the error is:', type(e))

The code above produces this error:

The error was: invalid literal for int() with base 10: 'Hello'
The type of the error is: <class 'ValueError'>
  • The type ValueError is a subclass of Exception
  • We'll discuss classes and subclasses later in the course
  • You can take advantage of the type of the error with multiple except statements.
  • Each except specifies what type of error you want to handle.
try: 
    foo = int('Hello') # Always an error
except ValueError as e: 
    print ('There is a ValueError:', e)
except Exception as e:
    print ('There is some other error:', e)
    print ('The type of the error is:', type(e))

This specifies what to do when a ValueError happens. All other errors will be handled differently. Here's the output:

There is a ValueError: invalid literal for int() with base 10: 'Hello'

Order of Except Matters!

  • Every ValueError is an Exception
  • But not ever Exception is a ValueError.
  • The except statements are traversed in order.

This is an error:

try: 
    foo = int('Hello') # Always an error
except Exception as e:
    # ValueErrors are Exceptions... 
    print ('There is some other error:', e)
    print ('The type of the error is:', type(e))
except ValueError as e: 
    # This will never run...
    print ('There is a ValueError:', e)

Luckily, Cloud9 IDE detects this error.

Throwing Exceptions

  • You can raise an exception with the raise statement.
  • It's useful when the code that detects the error doesn't know how to recover from the error.
try: 
    if number < 5 : 
        raise ValueError('Oh no! The number is less than 5')
except ValueError as e: 
    print ('There is a ValueError:', e)
  • If the number is less than 5 the error is raised.
  • Otherwise the code runs normally.
  • Most of the time the raise statement is not near the except statement
  • Exceptions allow flexibility in where you handle errors.

Here's an example of a more typical way to raise and handle exceptions:

def test_number(number) :
    if number < 5 : 
        raise ValueError('Oh no! The number is less than 5')
 
try: 
    test_number(number)
    print ('The number is correct!')
except ValueError as e: 
    print ('Bad Number:', e)
  • The raise statement causes the stack to unwind
  • In the example above the caller is notified, but
    • If the caller doesn't catch the error the caller of the caller gets a chance
    • If the error reaches the top level Python prints the exception and exits.

Finally!

  • Exceptions can cause a lot of code to be skipped.
  • They can terminate a function in its tracks.
  • Sometimes you need to make sure that cleanup happens even when an exception occurs.
  • Statements inside of a finally statement happen no matter what.

Here's an example of using finally to close a file in the event of an error:

f = open('input.txt')
try : 
    number = int(f.readline()) # Will fail if the input is not a number. 
except ValueError as e : 
    print ('Ooops!', e)
finally:
    # No matter how we leave try this will happen.
    f.close()

Jinja2 and if/else

  • Templates often need conditional statements.
  • In the advanced project for this week you will have to change tags and inputs based on program flow.
  • Jinja2 has special syntax for conditional HTML

Here's an example of an if statment in Jinja2:

{% if door == 1 %}
    <img src="resources/goat.png" width="100px">
{% else %}
    <img src="resources/door.png" width="100px">
{% endif %}
  • The example will render one of the two img tags, depending on the value of the door variable.
  • The door variable is passed into the template just like any other template variable.

An example of how you could call the template above:

@app.route('/')
def index() :
    return render_template('template.html', door=1)

Example Code

Example code from today's lecture can be downloaded here:

week8.tar.gz