Functions, Strings, Booleans, Doctests

Lesson Overview

  • Interpreter
  • Mathematics — integer/float
  • Style
  • Black box examples
  • Boolean logic
  • String introduction
  • String concatenation
  • String loops

Big Picture Strategy – Divide and Conquer

Q: What is the main technique for solving big problems?
A: Divide and conquer.

  • Divide the program into functions
  • Work on one function at a time (a.k.a. decomposition)
  • As we build up CS techniques… many techniques are in service of the big-picture goal

Data flow picture

Here is a way of looking at a program.

You have some files with data in them. You write code to load the data into Python in one form, then compute a transform into another form. Then a further computation produces an ‘answer’ form. You publish the answer and get tweets of praise — the coding lifecycle! You can think of this as a sort of ‘data flow’, from the original data to the final output.

‘Black Box’ Function Model

Black-box model of a function: function runs with parameters as input, returns a value. All the complexity of its code is sealed inside.

The black box model makes it easy to call the function – provide data you have as the input, call the function, get back an answer.

Strategy – One Function at a Time

For Divide and Conquer, want to be able to work on each function separately, one at a time. We need to keep the functions sealed off from each other as much as possible. The black box model works well for this, narrowing the interactions to just the input and output data for each function.

Write Black Box Cases

Here, we’ll work through code some black box examples.

We’ll think about the various cases for the input, since ultimately the code needs to handle all possible input cases. Thinking about the various cases is an easy way to get started with code for a function.

1. winnings() example

  • This is a first, simple example, just showing the mechanics
  • Say we are writing a function for a lottery game
  • Rules: input is an int score 0..10 inclusive
  • score 0-4 — winnings is score * 10
  • score 5-10 — winnings is score * 12
  • Can make a table showing output for each input

Function Input: Parameter

def winnings1(score):
    ...
  • The parameters to a function are its inputs – left side of black-box picture
  • e.g. score is the input here
  • Each parameter is like a variable with a value in it
  • Code inside the function just uses the parameter value – easy

Function Output: return result

def winnings1(score):
    return score * 10

When a return line runs in a function:

  1. It exits the run of the function immediately, and
  2. It specifies the return value that will go back to the caller. Often called the ‘result’ of the function.

So the return statement makes the output of the function.

winnings1() example

Loading Challenge
Pass Fail Error

Challenge output format

  • Code challenges generate a table of outputs
  • It calls the function with many inputs
  • Shows the function result one per row
  • First ‘call’ column is the input
  • Second ‘got’ column is what the function returned
  • Easy to see the function’s behaviour this way
  • Black box model: think of function as its inputs and outputs

Experiment 1

def winnings1(score):
    return score * 10
  • Trying one line for the function: return score * 10.
  • Look at the table of output
  • See the basic roles of parameter/return
  • But this output is wrong half the time

if-return Pick-Off Strategy

The function needs to handle all possible input cases.

  • Have if-logic to detect one case
  • Return the answer for that case, exiting the function
  • Lines below have if-return logic for other cases

Code is ‘picking off’ the cases one-by-one. As we get past if-checks, input must be a remaining case.

Another analogy: a coin sorting machine. A coin rolls past holes, smallest to largest.

  • 1st hole – dime
  • 2nd hole – penny
  • 3rd hole – nickel
  • 4th hole – quarter

A dime never makes it to the fourth hole – it’s picked off earlier.

Experiment 2

def winnings1(score)
    if score < 5:
        return score * 10

Add if-logic to pick off the < 5 case. Run it. We can see that it’s right for half the cases.

None Result
  • None is the default return value of a function
  • None is returned if there is no explicit return value
  • This can happen by ‘falling off the end’ of the function, i.e. all its lines have run and the function is finished
  • Above example, we see None if score >= 5.
  • If you see None like this, look at your code and think how is it not doing a return?

Experiment 3 – Very Close

def winnings1(score):
    if score < 5:
        return score * 10
    if score >= 5:
        return score * 12

Add pick-off core for the score >= 5 case. This code returns the right result in all cases. There is just one tiny logical flaw.

Experiment 4 – Perfect

def winnings1(score):
    if score < 5:
        return score * 10

    # Run gets here: we know score >= 5
    return score * 12
  • Each pick-off recognises a case and exits the function
  • Therefore, for lines below the pick-off, the picked-off case is excluded
  • That is, the score >= 5 test is unnecessary
  • This helps with your one-at-a-time attention:
    • Work on code for case 1
    • When that’s done, put it out of mind
    • Work on case 2, knowing case 1 is out of the picture

What about this code?

What about this solution…

def winnings1(score):
    if score < 5:
        return score * 10
        return score * 12

That does not work. The second return is in the control of the if because of the indentation. It never runs because the line above exits the function. Obviously indentation is very significant for what code means in Python.

Think like a programmer — Systematic Cases

  • Think like a programmer, you know the code needs to work on all the cases
  • Natural to think about case-1, then case-2, …
  • This is helpful when you are staring at a blank screen
  • Think .. ok, what’s one case, write code to pick-off that one

winnings2() challenge

Here’s another challenge for practice.

Say there are 3 cases. Use a series of if-return to pick them off. Need to think about the order. Need to put the == 10 case early.

Winnings2: The int score number is in the range 0..10 inclusive. Bonus! if score is 10 exactly, winnings is score * 15. If score is between 4 and 9 inclusive, winnings is score * 12. if score is 3 or less, winnings is score * 10. Given int score, compute and return the winnings.

Loading Challenge
Pass Fail Error

Solution

“`
def winnings2(score):
if score == 10:
return score * 15

if score >= 4:  # score <= 9 is implicit
        return score * 12

    # All score >= 4 cases have been picked off.
    # So score < 4 here
    return score * 10

    # Here the cases are handled from 10 to 0.
    # The opposite order would be fine, too.