5. Logic, Booleans, More Functions

5.1. The Boolean type

  • A value that is either True or False (and nothing else) has type Boolean.

  • We’ve used comparison operators (e.g., <, >, ==) in conditionals.

  • What’s going on “under the hood” with the comparison, though?
    >>> 5 > 2
    True
    
    >>> 5 < 2
    False
    
  • A comparison like a > b is just an expression, like a + b.

  • The difference is that the value it produces isn’t an integer, it’s either True or False

  • This may seem like a subtle thing, but it’s a big deal:
    • An operator that takes 2 numbers and produces a number:
      • 1 + 1 -> 2

    • An operator that takes 2 booleans and produces a boolean:
      • True and False -> False

    • An operator that athes 2 numbers and produces a boolean:
      • 1 < 2 -> True

    >>> type(5 > 2)
    <class 'bool'>
    

Activity

Write a function is_negative(n) that returns True if the argument n is negative and False otherwise.

Verify that the return type is correct.

5.2. More about returns

  • We’ve already seen that functions can return a value at the end.

  • In fact, a function can return a value at any time, not just the end.

  • We can take advantage of this fact to have multiple returns!:

    def divisible_by(a, b):
        if a % b == 0:
            return True
        else:
            return False
    

Activity

  • What is the result of the function call divisible_by(4, 2)?

  • How about divisible_by(4, 3)?

  • Now write a new function not_divisible_by(a, b) that returns True when a is not divisible by b and False otherwise.

  • Now write this function to do the same thing with only 1 return statement.

  • Now write it with only 1 line of code within the function (so, 2 lines including the function header).

  • Functions returning Boolean values are pretty handy. Why? Where do you see yourself using them?

5.3. The function type

  • In Python, functions have a type, too:
    >>> type(divisible_by)
    <class 'function'>
    
  • Not all programming languages are so enlightened.

  • You can read up on first-class functions if you want to be a nerd about it.

  • This allows us to do some very “meta” things and quickly write code that is really general:

    def add(a, b):
        return a + b
    
    def subtract(a, b):
        return a - b
    
    def do_something(f, a, b):
        return f(a, b)
    

Activity

  • What is the value of do_something(add, 5, 7)?

  • How about do_something(substract, 5, 7)?

  • Now make sense of what exactly is happening!

  • If all of this weirds you out… good. You’re normal. Passing around functions is crazy weird stuff.

  • Don’t worry if you aren’t 100% confident on this yet. We’ll come back to it in more detail later.

5.4. Developing bigger programs

img/softeigineering.jpeg
  • The best way to do this is still a (very) open research problem in software engineering.

  • Here, I’m going to suggest bottom up, incremental, development.

  • Start with an empty function that returns a constant value (e.g., 0.0)

  • Try the function. Works? Ok, step 1 down.

  • Add 1 or 2 lines of code to accomplish part of what you want to do.

  • Try the function. Make sure those lines worked!

  • Repeat.

  • Build up your function incrementally and test at each increment.

  • The alternative is to try to sit down and bang out the whole function in one go.
    • If you’re perfect, this is faster.

    • Otherwise… you’ll spend a lot of time debugging.
      • You’re already going to spend a lot of time debugging, so don’t give yourself more work.

    • Besides, I’m sorry, but you’re not perfect.

Activity

Build a function to compute compound interest given a starting amount(P), an annual interest rate (r), the number of compounding periods per year(n) and the total number of years (t).

Your function should return the value of the principle plus the interest after compounding.

  • For bigger projects: break your problem down into a hierarchy of subproblems (remember, think in terms of levels of abstraction!).

  • Solve the easiest, smallest, subproblems first.

  • For us, solving means “writing a function to do it”.

  • Immediately after writing the function, test it right there and then.

  • Once you’ve written all the really easy, low level, functions, start combining them to write the higher level ones.