Today: xxxxxxx midterm prep, Doctests, exponentiation, modulus, num-histogram example
No new material shown today is on the midterm - the midterm is about topics on HW5, but we will do an additional HW5 dict example today.
Three priorities for a computer project.
Today, I'll show you some techniques where we have code that is already correct, but we can write it in a better, cleaner way. It's intuitively satisfying to have a 10 line thing, and shrink it down to 6 lines that reads better.
Already talked about Decomp-By-Var, which is in the same family of techniques - replace working code with a version that reads better.
You can think of every program as having some phrases of stock, idiomatic code, and then some phrases that are custom, idiosyncratic bits particular to that algorithm. We'll just say, use the idiomatic bits where they come up — easy to type in, easy to understand. Build your needed changes around the idiomatic code. The first 3 solutions above work in this way. The last, reverse5, is the opposite - manually build it vs. building on the capability of range().
Would that be "attesor"?
How many ways can you think of to reverse a string in Python?
'Hello' -> 'olleH'
Here are challenges for 5 different ways, each using different parts of Python. Each problem problem says "use xxx" to direct which language feature to use.
Aside: there is a scene in the Movie Amadeus where Motzart plays a piece one way, then gets under the piano, reaches hands up and plays it again upside down. I believe today this would be called a "flex"? youtube
The first two versions are the best. The are the best because they leverage foreach or for/i/range to hit all the chars, solving the problem without any error prone, manual index computation.
reverse = xxx line)
> reverse() problems
Work out the code for the first 2 or 3.
Fine: use the stock for/i/range(), compute needed rev_i from that (reverse3)
Not as good: compute rev_i manually, not leveraging the idiomatic for/i/range (reverse4 and reverse5)
> better - invariant problems
speeding(speed, birthday): Compute speeding ticket fine as function of speed and birthday boolean. Rule: speed under 55, fine is 100, otherwise 200. If it's your birthday, the allowed speed is 5 mph more. Challenge: change this code to be shorter, not have so many distinct paths.
The code below works correctly. How to write it better?
def speeding(speed, birthday):
if not birthday:
if speed < 50:
return 100
else:
return 200
else: # is birthday
if speed < 55:
return 100
else:
return 200
def speeding(speed, birthday):
# Setup limit var
limit = 50
if birthday:
limit = 55
# Invariant: limit holds value to use
if speed < limit:
return 100
return 200
Change this code to be better / shorter. Look at lines that are similar - make an invariant.
ncopies(word, n, suffix): Given name string, int n, suffix string, return
n copies of string + suffix.
If suffix is the empty string, use '!' as the suffix.
Challenge: change this code to be shorter,
not have so many distinct paths.
Before:
def copies(word, n, suffix):
result = ''
if suffix == '':
for i in range(n):
result += word + '!'
else:
for i in range(n):
result += word + suffix
return result
Solution: use logic to set "suffix" to hold the suffix to use for all cases. Later code just uses suffix vs. separate if-stmt for each case.
def copies(word, n, suffix):
result = ''
# Set suffix to be value to use regardless
if suffix == '':
suffix = '!'
# invariant: suffix is value to use
for i in range(n):
result += word + suffix
return result
At the smallest scale in the computer, information is stored as bits and bytes. In this section, we'll look at how that works.
How many different patterns can be made with 1, 2, or 3 bits?
| Number of bits | Different Patterns |
|---|---|
| 1 | 0 1 |
| 2 | 00 01 10 11 |
| 3 | 000 001 010 011 100 101 110 111 |
| Number of bits | Different Patterns |
|---|---|
| 1 | 0 1 |
| 2 | 00 01 10 11 |
| 3 | 000 001 010 011 100 101 110 111 |