Progress

Think Python, 2 chapters.

Intro to CS & Python, 2 lectures.

- 6/12 Intro to CS & Python – Dr. Ana Bell, Dr. Eric Grimson
- 1/22 Structures
- 2/30 AI – Dr. Patrick Winston
- 0/4 (0/11, 0/11, 0/5, 0/8) Math for CS
- 0/11 Puzzled
- ? EECS, Remedial 5/19 Think Python – Dr. Allen Downey

***

## Think Python, CH 4

Interface design. Dr. Downey covers the following concepts.

Generalization adds parameters to functions to make them able to perform a broader range of actions. Dr. Downey’s example is taking a function that draws a square and making it to draw regular polygons instead. It can still draw squares, but it can draw other polygons too.

“It is legal, and sometimes helpful, to include the names of the parameters in the argument list: polygon(bob, n=7, length=70)”

Refactoring rearranges code to maximize code reuse. It’s like factoring in math; you factor out the constants.

A development plan (verbatim):

- Start by writing a small program with no function definitions.
- Once you get the program working, encapsulate it in a function and give it a name.
- Generalize the function by adding appropriate parameters.
- Repeat steps 1–3 until you have a set of working functions. Copy and paste working code to avoid retyping (and re-debugging).
- Look for opportunities to improve the program by refactoring. For example, if you have similar code in several places, consider factoring it into an appropriately general function.

Dr. Downey covers docstrings in making functions. Unlike where I’ve seen it before (was that Dr. Bell’s example?), Dr. Downey starts the explanation of the function right after the first triple quote, not the next line.

“””Draws n line segments with the given length and angle (in degrees) between them. t is a turtle.

“””

Instead of:

“””

Draws n line segments with the given length and angle (in degrees) between them. t is a turtle.

“””

In the perennial debugging section of the chapter, Dr. Downey argues that as long as the required preconditions of the function are properly documented, failure to adhere to them is user error. Along with preconditions, he mentions postconditions. I don’t like his definition, so I’ll go with Wikipedia: “a condition or predicate that must always be true just after the execution of some section of code or after an operation in a formal specification”. Dr. Downey makes it sound like the execution of the function is also a postcondition which violates the “post” portion of the word. A precondition is before the function, a postcondition is after the function.

***

## Think Python, CH 5

Modulus operator. 7 % 3 = 1 because 7 / 3 has a remainder of 1. x % 10 gives the last digit of x. x % 100 gives the last 2 digits of x.

When covering logical operators, he points out that any number other zero is interpreted as “true”. I tested negative numbers and nonintegers. They are interpreted as true. When I put in 0, instead of returning False like I was expecting, it returned 0. When I put False into myBool variable, it returned False.

He covers chained and nested if statements.

Recursion. He covers functions that call themselves. I enjoyed his example. My version of Python requires parentheses for the print function.

```
>>> def countdown(n):
... if n <= 0:
... print("Blastoff!")
... else:
... print(n)
... countdown(n-1)
...
>>> countdown(3)
3
2
1
Blastoff!
>>> countdown(10)
10
9
8
7
6
5
4
3
2
1
Blastoff!
```

He covers stack diagrams for recursive functions, keeping track of what’s going on.

<module>

countdown – n→3

countdown – n→2

countdown – n→1

countdown – n→0

Infinite recursion doesn’t happen because Python caps it at 1,000.

Error messages in Python point to where a problem is discovered, not where it is caused.

***

## Turtles in Python

So in Chapter 4, Dr. Downey talked about using turtles and downloading something from his site. I wasn’t inclined to do so. But I did a search for “draw in Python” and found that in 3.9, turtles are baked into Python (https://docs.python.org/3/library/turtle.html). I only messed around with it briefly, but I might go back and do the turtle examples in chapters 4 and 5.

With turtles imported, I drew an 18 pointed star. This reminds me of the Spirograph I had when I was a kid.

```
>>> reset()
>>> for x in range(18):
... turtle.forward(100) #pixels
... turtle.right(100) #degrees
```

***

## Tuples, Lists, Aliasing, Mutability, and Cloning; Intro to CS and Python lecture #5

Tuple: an ordered sequence of elements. You can mix element types. Tuples are immutable.

t = () # declares an empty tuple

t = (2, “MIT”, 3)

t[0] # evaluates to 2

(2, “MIT”, 3) + (5, 6) # evaluates to (2, “MIT”, 3, 5, 6)

t[1:2] # slicing the tuple results in (“MIT”, ). The comma in the parentheses indicates that it’s a tuple. Without the comma, it’s a string.

t[1:3] # slicing the tuple results in (“MIT”, 3)

len(t) # evaluates to 3

t[1] = 4 # results in error, can’t modify tuple object.

Tuples are convenient for swapping variable values.

You can’t swap variables by:

x = y

y = x

because you’re overwriting x.

You can:

temp = x

x = y

y = temp

But with tuples, it’s one line:

(x, y) = (y, x)

Functions are allowed to only return one object. Tuples are objects with multiple objects inside. So you can use tuples to get multiple things from a function.

```
def quotient_and_remainder(x, y):
q = x // y
r = x % y
return(q, r)
```

You can iterate over tuples.

```
def get_data(aTuple):
nums = ()
words = ()
for t in aTuple:
nums = nums + (t[0],)
if t[1] not in words:
words = words + (t[1],)
min_n = min(nums)
max_n = max(nums)
unique_words = len(words)
return (min_n, max_n, unique_words)
```

Lists are a lot like tuples, but they are shown by square brackets instead of parentheses and are *mutable*!

Common pattern, iterate over list elements:

```
total = 0
for i in L:
total += i
print(total)
# is equivalent to:
total = 0
for i in range(len(L)):
total += L[i]
print(total)
# the first is more Pythonic.
```

Add elements to the list:

L = [2, 1, 3]

L.append(5) # changes the list L to [2, 1, 3, 5]

The dot in “.append” indicates something being done to an object. In the past I’ve found this frequently in VBA for Excel. Objects have data, methods, and functions. For instance, math.pi calls up the pi value from the math module.

L1 = [2, 1, 3]

L2 = [4, 5, 6]

L3 = L1 + L2 # L3 is [2, 1, 3, 4, 5, 6]. L1 and L2 remain unchanged.

L1.extend([0, 6]) # mutated L1 to [2, 1, 3, 0, 6].

L = [2, 1, 3, 6, 3, 7, 0]

L.remove(2) # L = [1, 3, 6, 3, 7, 0]. The function finds the first value 2 and removes it.

L.remove(3) # L = [1, 6, 3, 7, 0].

del(L[1]) # L = [1, 3, 7, 0]. The del function deletes nth element of the list.

L.pop() # function returns last element and deletes it. L = [1, 3, 7].

Converting lists to strings and back.

s = “I<3 cs”

list(s) # returns [‘I’, ‘<‘, ‘3’, ‘ ‘, ‘c’, ‘s’]. Note the returned object is a list.

s.split(‘<‘) # returns [‘I’, ‘3 cs’]. Again, string becomes list. If called without a parameter, split() splits on spaces.

L = [‘a’, ‘b’, ‘c’]

”.join(L) # returns “abc”. Note list becomes a string.

‘ ‘.join(L) # returns “a b c”.

Other list operations

L = [9, 6, 0, 3]

sorted(L) # returns a sorted list, but doesn’t modify L.

L.sort() # sorts L.

L.reverse() # reverse sorts L.

As lists are mutable, if you change one and refer to it in multiple places, it will change in each of those places.

a = 1

b = a

print(a)

> 1

print(b)

> 1 # because b is referring to a.

warm = [‘red’, ‘yellow’, ‘orange’]

hot = warm

hot.append(‘pink’)

print(hot)

> [‘red’, ‘yellow’, ‘orange’, ‘pink’]

print(warm)

> [‘red’, ‘yellow’, ‘orange’, ‘pink’]

Get around this by cloning (copying) the list for the new variable.

cool = [‘blue’, ‘green’, ‘grey’]

chill = cool[:] # that sweet cloning action

chill.append(‘black’)

print(chill)

> [‘blue’, ‘green’, ‘grey’, ‘black’]

print(cool)

> [‘blue’, ‘green’, ‘grey’] # because you cloned it and didn’t mess with the clone.

You can have lists in lists.

## Recursion and Dictionaries; Intro to CS and Python lecture #6

This lecture was taught by Dr. Eric Grimson.

Recursion can be thought of as reduce and conquer. It’s a program that calls itself.

• It must have 1 or more base cases that are easy to solve. Once this is solved, the recursion ceases.

• It solve the same problem on some other input with the goal of simplifying the larger problem input.

```
def mult_iter(a, b):
result = 0
while b > 0:
result += a
b -= 1
return result
# This adds a to itself b times. The same, with recursion:
def mult(a, b):
if b == 1:
return a # the if is the base case, an exit clause.
else:
return a + mult(a, b-1)
```

So recursion keeps reducing the problem until it gets to something it can solve directly.

```
def fact(n):
if n == 1:
return 1
else:
return n*fact(n-1)
fact(5)
> 120
```

So, normally, if I return 1, that’s the output of the function. Why isn’t the output 1? Well, it is, five levels deep. Stack diagram:

Global scope → fact(5)

fact scope (5) → return 5 * fact(4)

fact scope (4) → return 4 * fact(3)

fact scope (3) → return 3 * fact(2)

fact scope (2) → return 2 * fact(1)

fact scope (1) → return 1

Global scope → fact(5)

fact scope (5) → return 5 * fact(4)

fact scope (4) → return 4 * fact(3)

fact scope (3) → return 3 * fact(2)

fact scope (2) → return 2 * 1

Global scope → fact(5)

fact scope (5) → return 5 * fact(4)

fact scope (4) → return 4 * fact(3)

fact scope (3) → return 3 * 2

Global scope → fact(5)

fact scope (5) → return 5 * fact(4)

fact scope (4) → return 4 * 6

Global scope → fact(5)

fact scope (5) → return 5 * 24

Global scope → 120

Dictionaries store pairs of data, a key and a value.

my_dictionary = {}

grades = {‘Ana’: ‘B’, ‘John’:’A+’, ‘Denise’:’A’, ‘Katy’:’A’}

grades[‘Sylvan’] = ‘A’ # add an entry

‘John’ in grades # returns True. This means you can test if a key exists.

‘Daniel’ in grades # returns False.

del(grades[‘Ana’]) # deletes Ana entry in the dictionary.

Dictionaries can have any data type for values.

Keys must be an immutable data type. Keys must be unique. No order is guaranteed. Dictionaries match “keys” to “values”.