- One piece of paper, front and back, handwritten, is allowed on the midterm. You can write as small as you like, and can bring a magnifying glass.
- You can also use the study guide that will be made for you and printed and waiting for you at your exam seat.
- Check Piazza for more resources.

```
def square(x):
return mul(x, x)
def sum_squares(x, y):
return square(x) + square(y)
```

What does `sum_squares`

need to know about `square`

?

`square`

takes one argument.`square`

computes the square of a number.

What does `sum_squares`

**not** need to know about `square`

?

`square`

has the intrinsic name`square`

.`square`

computes the square by calling`mul`

.

```
def square(x): def square(x):
return pow(x, 2) return mul(x, x-1) + x
```

Even if `square`

were bound to a built-in function, `sum_squares`

would still work identically. The mechanisms of `square`

are irrelevant to `sum_squares`

.

Names should convey the meaning or purpose of the values to which they are bound. The type of value bound to the name is best documented in a function's docstring.

Function names typically convey their effect (`print`

), their behavior (`triple`

), or the value returned (`abs`

).

Any of the following reasons makes it fair to add a new name:

- Repeated compound expressions

```
if sqrt(square(a) + square(b)) > 1:
x = x + sqrt(square(a) + square(b))
# avoid repeating sqrt(square(a) + square(b))
hypotenuse = sqrt(square(a) + square(b))
if hypotenuse > 1:
x = x + hypotenuse
```

- Meaningful parts of complex expressions

```
x1 = (-b + sqrt(square(b) - 4 * a * c)) / (2 * a)
# make the quadratic formula easier to discern
discriminant = square(b) - 4 * a * c
x1 = (-b + sqrt(discriminant)) / (2 * a)
```

More tips:

- Names should generally be short and concise, but they can be long if they help document your code.
`average_age = average(age, students)`

is preferable to`aa = avg(a, st)`

.

- Names should generally be descriptive, but they can be short if they represent generic quantities: counts, arbitrary functions, arguments to mathematical operations, etc.
`n, k, i`

are usually integers`x, y, z`

are usually real numbers`f, g, h`

are usually functions

Will get back to this.

The following is a giant example that takes everything learned so far into account. This is the remainder of today's lecture.

```
from wave import open
from struct import Struct
from math import floor, sin
frame_rate = 11025
def encode(x):
"""Encode float x between -1 and 1 as two bytes.
"""
i = int(16384 * x)
return Struct('h').pack(i)
def play(sampler, name='song.wav', seconds=2):
"""Write the output of a sampler function as a wav file.
"""
out = open(name, 'wb')
out.setnchannels(1)
out.setsampwidth(2)
out.setframerate(frame_rate)
t = 0
while t < seconds * frame_rate:
sample = sampler(t)
out.writeframes(encode(sample))
t = t + 1
out.close()
def tri(frequency, amplitude=0.3):
"""A continuous triangle wave."""
period = frame_rate // frequency
def sampler(t):
saw_wave = t / period - floor(t / period + 0.5)
tri_wave = 2 * abs(2 * saw_wave) - 1
return amplitude * tri_wave
return sampler
c_freq, e_freq, g_freq = 261.63, 329.63, 392.00
# play(tri(c_freq))
c = tri(c_freq)
e = tri(e_freq)
g = tri(g_freq)
low_g = tri(g_freq/2)
def both(f, g):
return lambda t: f(t) + g(t)
# play(both(c, e))
# play(both(c, both(e, g)))
# play(both(c, both(e, g)), seconds=1)
def note(f, start, end, fade=.1):
def sampler(t):
seconds = t / frame_rate
if seconds < start or seconds > end:
return 0
elif seconds < start + fade:
return (seconds - start) / fade * f(t)
elif seconds > end - fade:
return (end - seconds) / fade * f(t)
else:
return f(t)
return sampler
# play(note(c, 0, 1/4))
# play(both(note(c, 0, 1/4),
# note(e, 1/2, 1)))
def mario(c, e, g, low_g):
z = 0
song = note(e, z, z + 1/8)
z += 1/8
song = both(song, note(e, z, z + 1/8))
z += 1/4
song = both(song, note(e, z, z + 1/8))
z += 1/4
song = both(song, note(c, z, z + 1/8))
z += 1/8
song = both(song, note(e, z, z + 1/8))
z += 1/4
song = both(song, note(g, z, z + 1/4))
z += 1/2
song = both(song, note(low_g, z, z + 1/4))
return song
def mario_at(octave):
c = tri(c_freq * octave)
e = tri(e_freq * octave)
g = tri(g_freq * octave)
low_g = tri(g_freq/2 * octave)
return mario(c, e, g, low_g)
play(both(mario_at(1), mario_at(0.5)))
```