Today - big picture divide and conquer, black box examples, boolean logic, string introduction, string +=, string for/i/range loop -->
We want to build this program, and we can think of it as a mess of code.
The one key strategy for CS is Divide and Conquer. The first form of this is dividing the program up into individual functions, like this.
For today .. focus on what one functions looks like. Especially how data gets in and out of a function, and ultimately we can fit all the functions together. Many bits of Python technology we will see are in service of this program-of-functions strategy.
For Divide-and-Conquer strategy to work, we want to work on one function at a time. To do that, we need the functions to be independent of each other. When working on a function, we're just looking at its code, not having to think about lines from other functions.
We will characterize each function by its inputs and outputs. Imagine the walls of the function are nice and thick — so it only interacts with its environment through its well defined inputs and outputs. This design keeps the functions independent, but with just enough input/output to interact with the other functions.
In Python, a function's input is its parameters, and its output is from the Python return directive.
Say we are working on an app where people type in phone numbers, like 555-1212.
Suppose that sometimes the user types in a phone number kind of incompetently, with extra spaces and dashes. Imagine a function fix_phone() that takes in the malformed number as an input, and returns a cleaned up phone number as output, with the digits in the right places and one dash.
Think of it as a black box with an input and output, that would look like this:
You could think about fix_phone(), you could think of all the different inputs it should handle, and what the output should be for each one. These leads naturally to thinking about the "Cases" for a function — a table of inputs, and for each input, what should be the output.
In this case, we'll say that if an input number does not have 7 digits, then it is unfixable, and in that case the output should be the special value None, signalling that that input was beyond repair.
Since the function computes using its input data, if called two times with the same inputs, it should produce the same outputs.
Functions can be very abstract. Cases are more concrete way to think about a function — what inputs to handle, and what the output should be for each one.
Getting started — thinking about the various cases is a good way to get started with the code for a function. We might use the word systematic to describe this approach, thinking through all the cases to make sure each is handled.
Now we'll starting coding up many black-box input/output functions, starting in the logic 1 section on the experimental server.
def winnings1(score):
...
score -> winnings 0 0 1 10 2 20 3 30 4 40 5 60 # 12x kicks in here 6 72 7 84 8 96 9 108 10 120
Think about this as a black-box function, inputs and outputs.
def winnings1(score):
...
return result
def winnings1(score):
return score * 10
You can type these in and hit the Run button as we go or just watch as we go. The results are pretty easy to follow.
def winnings1(score):
return score * 10
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
def winnings1(score):
if score < 5:
return score * 10
if score >= 5:
return score * 12
Add pick-off code for the score >= 5 case (>= means greater-or-equal). This code returns the right result in all cases. There is just at tiny logical flaw.
def winnings1(score):
if score < 5:
return score * 10
# Run gets here: we know score >= 5
return score * 12
What about this solution...
def winnings1(score):
if score < 5:
return score * 10
return score * 12
The above 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.
Similar practice example on your own.
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.
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.
For more detail, see guide Python Boolean
Can try these in the interpreter (Interpreter)
>>> n = 5 # assign to n to start >>> n == 6 False >>> n == 5 True >>> n != 6 True >>> >>> n < 10 True >>> n < 5 # < is strict False >>> >>> n <= 5 # less-or-equal True >>> >>> n > 0 True
and or notand or notSay we have temp variable is a temperature, and is_raining is a Boolean indicating if it's raining or not. Here are some examples to demonstrate and or not:
# have: int temp, boolean is_raining
# OR: one or the other or both are true
# AND: both must be true
# Say we want to stay inside
# if it's cold or raining...
if temp < 50 or is_raining:
print('staying inside!')
# Say we do want to go outside if
# it's snowing...
if temp < 32 and is_raining:
print('yay snow!')
Q: What is the code to detect if the temp is over 70 and it's not raining?
if -what goes here?-:
print('Sunny and nice!')
and ExampleSuppose we have this code, and n holds an int value.
if n > 0 and n < 10: # get here if test is True
What must n be inside the if-statement? Try values like 0 1 2 3 . 8 9 10
You can work out that n must be a an int value in the range 1..9 inclusive.
xxx == TrueIn an if or while test, do not add == True or == False to the test - though the English phrasing of it does tend to include those words.
Do not write it this way:
if is_raining == True: # NO not like this
print('raining')
Write it this way:
if is_raining: # YES like this
print('raining')
The if/while checks if the test is True or False on its own.
is_teen(n): Given an int n which is 0 or more. Return True if n is a "teenager", in the range 13..19 inclusive. Otherwise return False. Write a boolean test to pick off the teenager case.
Solution
def is_teen(n):
# Use and to check
if n >= 13 and n <= 19:
return True
return False
# Future topic: possible to write this
# as one-liner: return n >= 13 and n <= 19
A similar example for practice.
Lottery scratcher game: We have three icons called a, b, and c. Each is an int in the range 0..10 inclusive. If all three are the same, winnings is 100. Otherwise if 2 are the same, winnings is 50. Otherwise winnings is 0. Given a, b and c inputs, compute and return the winnings. Use and/or/== to make the tests.
Solution:
def scratcher(a, b, c):
# 1. All 3 the same
if a == b and b == c:
return 100
# 2. Pair the same (3 same picked off above)
if a == b or b == c or a == c:
return 50
# 3. Run gets to here, nothing matched
return 0
For more detail, see guide Python Strings
>>> len('Hello')
5
>>> s = 'Hello' # Equivalently
>>> len(s)
5
>>> len('x')
1
>>> len('')
0
''
s[1]>>> s = 'Python' >>> s[0] 'P' >>> s[1] 'y' >>> s[4] 'o' >>> s[5] 'n' >>> s[6] IndexError: string index out of range
>>> s = 'Python' >>> s[0] # read ok 'P' >>> s[0] = 'X' # write not ok TypeError: 'str' object does not support item assignment
>>> a = 'Hello' >>> b = 'there' >>> a + b 'Hellothere' >>> a 'Hello'
We've already used = to set a variable to point to a value. The code below sets s to point to the string 'hello'.
s = 'hello'
What if we use = to set an existing variable to point to a new value? This just changes the variable to point to the latest value, forgetting the previous value. The assignment = could be translated to English as "now points to".
s = 'hello' # change s to point to 'bye' s = 'bye'
s = s + something>>> s = 'hello' >>> s = s + '!' >>> # Q: What is s now?
Answer: s is 'hello!' after the two lines. So s = s + xxx is a way of adding something to the right side of a string. The following form does the exactly the same thing using += as a shorthand:
>>> s = 'hello' >>> s += '!'
Use a series of += to add on the end.
>>> s = 'hello' >>> s += '!' >>> s += '!' >>> s 'hello!!'
How to write a loop to look at every char? Super common to do this.
range(len(s))Generate index numbers with range():
range(len(s)) -> [0, 1, 2, 3, 4, 5]
This has lots of syntax, but it is idiomatic and we will use it many times.
for i in range(len(s))
# use s[i]
This is the standard, idiomatic loop to go through all the index numbers.
It's traditional to use a loop variable with the simple name i with this loop. Inside the loop, use s[i] to access each char of the string.
double_char(s): Given string s. Return a new string that has 2 chars for every char in s. So 'Hello' returns 'HHeelllloo'. Use a for/i/range loop.
Solution code
def double_char(s):
result = ''
for i in range(len(s)):
result = result + s[i] + s[i]
return result
If we have time, students do one. Look at each char, like double_char().
'xyz' -> '!x!!y!!z!'
Also, see the experimental server section string2 for many problems like double_char()
Optional - this is a neat feature, not sure if we're doing it today.
The experimental server has a feature to give a little insight about what's going on inside the loop.
Add inside the loop: print(i, s[i])
def double_char(s):
result = ''
for i in range(len(s)):
print(i, s[i])
result = result + s[i] + s[i]
return result
This will print one line for each iteration of the loop, showing what i and s[i] are as the loop runs.
Recall that the print() output is separate from the formal return output of the function. In the experimental server, the print output is shown below the function result, looking like this for the 'xyz' input:
print(i, s[i]) - Think About OutputSay the input is 'xyz'
Q: How many iterations will the loop run?
A: 3 - it runs through the index numbers 0, 1, 2
Q: What lines will print(i, s[i]) produce?
A:
0 x 1 y 2 z