## Chapter 1

1. Computers use binary numbers because it's easier to build electronic devices reliably if they only have to distinguish between two electric states.
1. 6 = 110
2. 44 = 101100
3. 72 = 1001000
4. 131 = 10000011
1. 100 = 4
2. 1011 = 11
3. 101010 = 42
4. 1001110 = 78
• Mix the dry ingredients.
• Cream the butter and sugar.
• Beat in the eggs.
• Stir in the dry ingredients.
• Set the oven for the appropriate temperature.
• Set the timer.
• Place the cookies into the oven.
• Allow the cookies to bake.
• Mix the ingredients for the frosting.
2. The legal identifiers shown are `printed`, `annual_salary`, `abc`, `sum_of_data`, and `b4`.
3. c. `print("Hello, world!")`
4. Output of statements:

```"Quotes" Slashes \// How '"confounding' "\" it is! ```
5. Output of statements:

```name age height Archie 17 5'9" Betty 17 5'6" Jughead 16 6' ```
6. Output of statements:

```Shaq is 7'1 The string "" is an empty message. \'"" ```
7. Output of statements:

``` a b c" \\ " ''' C: in he downward spiral ```
8. Output of statements:

```Dear "DoubleSlash" magazine, Your publication confuses me. Is it a \\ slash or a //// slash? Sincerely, Susan "Suzy" Smith ```
9. `print` statements to produce desired output:

```print("\"Several slashes are sometimes seen,\"") print("said Sally. \"I've said so.\" See?") print("\\ / \\\\ // \\\\\\ ///") ```
10. `print` statements to produce desired output:

```print("This is a test of your") print('knowledge of "quotes" used') print("in 'string literals.'") print() print("You're bound to \"get it right\"") print("if you read the section on") print("''quotes.''") ```
11. `print` statement to produce desired output:

```print("/ \\ // \\\\ /// \\\\\\") ```
12. Mistakes in the program:

1. line 1: The keyword `def` is missing.
2. line 2: A closing `)` is missing.
3. line 3: The text inside the parentheses should be in quotes.
13. Mistakes in the program:

1. line 2: Should be indented.
2. line 3: Should be indented.
3. line 3: A closing `"` mark is missing.
14. a. `def example():`
15. Output of the program:

```This is message1.
This is message2.
This is message1.
Done with message2.
Done with main.
```
16. Output of the program:

```Inside first function
Inside third function
Inside first function
Inside second function
Inside first function
Inside second function
Inside first function
Inside third function
Inside first function
Inside second function
Inside first function
```
17. Output of the program:

```Inside first function
Inside first function
Inside second function
Inside first function
Inside third function
Inside second function
Inside first function
Inside first function
Inside second function
Inside first function
Inside third function
```
18. Output of the program:

```Inside second function
Inside first function
Inside first function
Inside second function
Inside first function
Inside third function
Inside first function
Inside second function
Inside first function
```
19. Mistakes in the program:

1. line 2: The line is indented in one too far.
2. line 2: The contents of the parentheses aren't in quotes.
3. line 3: The function call is misspelled.
4. line 5: Parentheses are missing after the function name.
5. line 5: A `:` is missing after the function name and parentheses.
6. line 6: A closing `)` is missing.
7. line 7: The `"`s inside the string need to be escaped.
8. line 7: The line shouldn't include a `;`.

## Chapter 2

1. Results of expressions:

1. `8`
2. `11`
3. `6`
4. `4`
5. `33`
6. `-16`
7. `6.4`
8. `6`
9. `30`
10. `1`
11. `-1`
12. `5.0`
13. `2`
14. `18`
15. `3`
16. `4`
17. `4`
18. `15`
19. `8`
20. `1`
2. Results of expressions:

1. `9.0`
2. `9.6`
3. `2.0`
4. `6.0`
5. `6.0`
6. `8.0`
7. `1.25`
8. `3.0`
9. `3.0`
10. `3.0`
11. `5.0`
12. `6.4`
13. `37.0`
14. `8.5`
15. `9.6`
16. `4.0`
17. `4.8`
18. `25.5`
3. e. `grade = 4.0`
4. Last digit: `number % 10`
5. Mistakes in the program:

1. line 3: There should be a `,` between `is"` and `x`.
2. line 6: The `, x` should be outside the quotes.
3. line 9: The word `int` should be omitted.
4. line 11: The word `and` should be surrounded by quotes.
• Second-to-last digit: `(number % 100) // 10` or `(number // 10) % 10`
• Third-to-last digit: `(number % 1000) // 100` or `(number // 100) % 10`
6. Values of `a`, `b`, and `c` after the code:

```            a: 6
b: 9
c: 16
```
7. Values of `first` and `second` after the code:

```            first: 19
second: 8
```
The code swaps the values of the variables `first` and `second`.
8. Rewritten shortened version of the code:

```first = 8,
second = 19
first += second
second = first - second
first -= second
```
9. Values of `i`, `j`, and `k` after the code:

```i: 4
j: 2
k: 1
```
10. Output of code:

```46
36
23
13
```
11. Version of the program that uses variables to avoid redundant expressions:

```def main():
# Calculate my pay at work, based on how many hours I worked each day
total_hours = 4 + 5 + 8 + 4
salary = 8.75
pay = total_hours * salary
tax_rate = 0.20
taxes_owed = pay * tax_rate

print("My total hours worked:")
print(total_hours)
print("My hourly salary:")
print("\$" + str(salary))
print("My total pay:")
print(pay)
print("My taxes owed:")
print(taxes_owed)

main()
```
12. ```def main():
for i in range(1, 5):
print("2 times", i, "=", (2 * i))

main()
```
1. `2 * count`
2. `15 * count - 11`
3. `-10 * count + 40`
4. `4 * count - 11`
5. `-3 * count + 100`
13. ```for i in range(1, 7):
print(18 * i - 22)
```
14. Output of `odd_stuff` function:

```4
2
1
0
```
15. Output of loop:

```9 1
7 2
4 3
0 4
```
16. Output of loop:

```+---+
\   /
/   \
\   /
/   \
\   /
/   \
+---+
```
17. Output of loop:

```T-minus 5, 4, 3, 2, 1, Blastoff!
```
18. Output of loops:

```1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
```
19. Output of loops:

```****!****!****!
****!****!****!
```
1. `2 * line + 2 * SIZE`
2. `4 * line + (3 * SIZE)`
3. `-line + (2 * SIZE + 3)`
20. Table for output:

line`\``!``/`
10220
22182
34144
46106
5868
610210
• expression for `\` and `/`: `2 * line - 2`
• expression for `!`: `-4 * line + 26`
21. Table for output:

line`\``!``/`
10140
22102
3464
4626
• expression for `\` and `/`: `2 * line - 2`
• expression for `!`: `-4 * line + 18`
• generalized for constant: `-4 * line + (4 * SIZE + 2)`

## Chapter 3

1. ```15 42
10 25
```
2. ```1 3 5
1 3 5 7 9 11 13 15
1 3 5 7 9 11 13 15 17 19 21 23 25
```
3. ```1 2 3 4 5
1 2 3 4 5 6 7
1 2 3 4
number = 8
```
4. ```whom and who like it
it and him like whom
whom and him like him
stu and boo like who
her and him like who
```
5. ```touch your eye to your head
```
6. ```say coke not pepsi or pop
say soda not soda or pepsi
say pepsi not koolaid or pop
say say not pepsi or pepsi
```
7. ```def print_strings(s, n):
for i in range(1, n + 1):
print(s, end=" ")
print()
```
8. The `Temperature` program changes the value of its `tempc` parameter on line 9, but this doesn't affect the variable `tempc` in `main`. The (incorrect) output is:
```Body temp in C is: 0.0
```
9. results of `math` expressions:

1. `1.6`
2. `2`
3. `36.0`
4. `64.0`
5. `10.0`
6. `116.0`
7. `7`
8. `5`
9. `-5`
10. `8.0`
11. `11.0`
12. `102.0`
13. `17.0`
14. `20.0`
15. `13.0`
16. `14.0`
10. Output of the program:

```3 0
1 2 4
4 3
5 2 4
8 1
5 9 4
```
11. ```grade = 2.7

# min = 2.0
x = math.pow(2, 4)
# x = 16.0
x = math.sqrt(64)
# x = 8.0
count = 25
math.sqrt(count)
# count = 25
count = math.sqrt(count)
# count = 5

a = math.abs(math.min(-1, -3))
# a = 3
```
12. ```def count_quarters(cents):
return cents % 100 // 25
```
13. ```def main():
age = int(input("How old are you?"))
print("You have", (65 - age), "years until retirement.")

main()
```
14. ```number = int(input("Type an integer: "))
print(number, "times 2 =", (number * 2))
```
15. ```phrase = input("What is your phrase? ")
times = int(input("How many times should I repeat it? "))
for i in range(1, times + 1):
print(phrase)
```
16. Correct syntax to draw a rectangle:

e. `p.draw_rect(10, 20, 50, 30)`
17. Mistakes in the code:

1. On the second line, the call to `draw_line` should be made on the `DrawingPanel` `p`, not on nothing.
2. On the second line, the order of the parameters is incorrect.

The following is the corrected code:

```p = DrawingPanel(200, 200)
p.draw_line(50, 86, 20, 35)
```
18. The black rectangle is being drawn second, so it's covering up the white inner circle. The following code fixes the problem:

```panel = DrawingPanel(200, 100)
p.set_color("black")
p.fill_rect(10, 10, 50, 50)
p.set_color("white")
p.fill_oval(10, 10, 50, 50)
```
19. The program draws a series of progressively smaller black circles, each with its right and bottom edges touching the right and bottom corners of the window. Its output looks like this: ## Chapter 4

1. English statements translated into logical tests:

1. `z % 2 == 1`
2. `z <= math.sqrt(y)`
3. `y > 0`
4. `x % 2 != y % 2`
5. `y % z == 0`
6. `z != 0`
7. `abs(y) > abs(z)`
8. `(x >= 0) == (z < 0)`
9. `y % 10 == y`
10. `z >= 0`
11. `x % 2 == 0`
12. `abs(x - y) < abs(z - y)`
2. Results of relational expressions:

1. `True`
2. `False`
3. `True`
4. `False`
5. `True`
6. `False`
7. `False`
8. `True`
9. `True`
3. Mistakes in the program:

1. line 5: `=` should be `==`, and line should end with a colon
2. line 5: `smaller` is out of scope here (line 4 should be `smaller = minimum(a, b)`
3. line 10: `=>` should be `>=` (or better yet, no `if` test is needed)
4. Output of `if_else_mystery_1` calls:

Call Output
a. `if_else_mystery_1(3, 20)` `13 21`
b. `if_else_mystery_1(4, 5)` `5 6`
c. `if_else_mystery_1(5, 5)` `6 5`
d. `if_else_mystery_1(6, 10)` `7 11`
5. Output of `if_else_mystery_2` calls:

Call Output
a. `if_else_mystery_2(10, 2)` `10 6`
b. `if_else_mystery_2(3, 8)` `9 9`
c. `if_else_mystery_1(4, 4)2` `3 4`
d. `if_else_mystery_2(10, 30)` `29 30`
6. Code to read an integer from the user, then print `even` if that number is an even number or `odd` otherwise:

```number = int(input("Type a number: "))
if number % 2 == 0:
print("even")
else:
print("odd")
```
7. The code incorrectly prints that even numbers not divisible by 3 are odd. This is because the `else` statement matches the most closely nested `if` statement (`number % 3 == 0`), not the outer `if` statement. The following change corrects the problem.

```if number % 2 == 0:
if number % 3 == 0:
print("Divisible by 6.")
else:
print("Odd.")
```
8. Refactored code to reduce redundancy:

```a = 2
if x < 30:
x += 1
print("Python is awesome!", x)
```
9. Refactored code to reduce redundancy:

```times = int(input("Is your money multiplied 1 or 2 times? "))
donation = int(input("And how much are you contributing? "))
sums += times * donation
total += donation

if times == 1:
count1 += 1
elif times == 2:
count2 += 1
```

If the user could type any number, the code might need additional `if` statements to increment the proper count variable.

10. Code to read red/green/blue color:

```choice = input("What color do you want? ")
if choice.lower() == "r":
print("You have chosen Red.")
elif choice.lower() == "g":
print("You have chosen Green.")
elif choice.lower() == "b":
print("You have chosen Blue.")
else:
print("Unknown color:", choice)
```
11. The problem with the given `sum_to` function is that the `sum` variable needs to be declared outside the `for` loop. The following code fixes the problem:

```def sum_to(n):
sums = 0
for i in range(1, n + 1):
sums += i
return sums
```
12. The `count_factors` function shown will not return the right answer. It should count the factors using a a cumulative sum; it should not return inside the loop when it finds each factor. Instead, it should declare a counter outside the loop that is incremented as each factor is seen. The following code fixes the problem:

```def count_factors(n):
count = 0
for i in range(1, n + 1):
if n % i == 0:
count += 1
return count
```
13. The expression equals `6.800000000000001` rather than the expected `6.8` because of a roundoff error.

14. The expression `gpa * 3` equals `9.600000000000001` rather than the expected `9.6` because of a roundoff error. A fix would be to test that the value is close to `9.6` rather than exactly equal to it, as shown in the following code:

```gpa = 3.2
diff = abs(gpa * 3 - 9.6)
if diff < 0.1:
print("You earned enough credits.")
```
15. The preconditions of `print_triangle_type` function are that the three side lengths constitute a valid triangle. Namely:

• All three side lengths passed are >= 0.
• No side's length exceeds the sum of any two other sides.
16. The preconditions of the `get_grade` function are that the grade parameter's value is between 0 and 100.

17. The `median_of_3` code fails when `n3` is the smallest of the three numbers; for example, when the parameters' values are (4, 7, 2), the code should return 4 but instead returns 2. The method could be correctly written as:

```def median_of_3(n1, n2, n3):
if n1 < n2 and n1 < n3:
if n2 < n3:
return n2
else:
return n3
elif n2 < n1 and n2 < n3:
if n1 < n3:
return n1
else:
return n3
else: # n3 < n1 and n3 < n2
if n1 < n2:
return n1
else:
return n2
```

or the following shorter version:

```def median_of_3(n1, n2, n3):
return max(max(min(n1, n2), min(n2, n3)), min(n1, n3))
```
18. The code fails when more than one number is odd, because it uses `elif` rather than `if`. The tests should not be nested because they are not mutually exclusive; more than one number could be odd. The following code fixes the problem:

```def print_num_odd(n1, n2, n3):
count = 0
if n1 % 2 != 0:
count += 1
if n2 % 2 != 0:
count += 1
if n3 % 2 != 0:
count += 1
print(count, "of the 3 numbers are odd.")
```

The following version without `if` statements also works:

```def print_num_odd(n1, n2, n3):
count = n1 % 2 + n2 % 2 + n3 % 2
print(count, "of the 3 numbers are odd.")
```
19. Output of the program:

```efg
nopqrs

qr
```
20. Statement that tests to see whether a string begins with a capital letter:

```if "A" <= the_string <= "Z":
...
```
21. The following expression would produce the desired result:

```name = "Marla Singer"
space = name.find(" ")
last_name = name[(space + 1) :]
first_initial = name
last_name_first_initial = last_name + ", " + first_initial + "."
print(last_name_first_initial)
```

Alternatively, you could use this shorter version:

```name = "Marla Singer"
print(name[(name.find(" ") + 1):] + ", " + name + ".")
```
22. Code to examine a string and determine how many of its letters come from the second half of the alphabet (`'n'` or later):

```# assuming that the string is stored in the variable s
count = 0
for ch in s.lower():
if ch >= 'n':
count += 1
print(count, "letters come after n.")
```

## Chapter 5

1. Executes body 10 times. Output is:
`1 11 21 31 41 51 61 71 81 91`
2. Executes body 0 times. No output.
3. Loops infinitely. Output is:
```250
250
250
...
```
4. Executes body 3 times. Output is:
`2 4 16`
5. Executes body 5 times. Output is:
`bbbbbabbbbb`
6. Executes body 7 times. Output is:
```10
5
2
1
0
0
0
```
1. ```n = 1
while n <= maxs:
print(n)
n += 1
```
2. ```total = 25
number = 1
while number <= (total / 2):
total = total - number
print(total, number)
number += 1
```
3. ```i = 1
while i <= 2:
j = 1
while j <= 3:
k = 1
while k <= 4:
print("*", end="")
k += 1
print("!", end="")
j += 1
print()
i += 1
```
1. Output of `mystery` calls:
Call Output
a. `mystery(1)` `1 0`
b. `mystery(6)` `4 2`
c. `mystery(19)` `16 4`
d. `mystery(39)` `32 5`
e. `mystery(74)` `64 6`
2. Output of `mystery` calls:

Call Output
a. `mystery(19)` `19 0`
b. `mystery(42)` `21 1`
c. `mystery(48)` `3 4`
d. `mystery(40)` `5 3`
e. `mystery(64)` `1 6`
3. Code that generates a random integer between 0 and 10 inclusive:
```import random
num = random.randint(0, 10)
```
4. Code that generates a random odd integer between 50 and 99 inclusive.
```import random
num = random.randint(25) * 2 + 51
```
5. The `print_letters` code has a fencepost problem; it will print a dash after the last letter. The following code corrects the problem:
```def print_letters(text):
if len(text) > 0:
print(text, end="")
for i in range(1, len(text)):
print("-" + text[i], end="")
print()   # to end the line of output
```
6. Sentinel loop that repeatedly prompts the user to enter a number and, once the number `-1` is typed, displays the maximum and minimum numbers that the user entered:
```SENTINEL = -1
num = int(input("Type a number (or " + str(SENTINEL) + " to stop): "))
mins = num
maxs = num
while num != SENTINEL:
if num < mins:
mins = num
elif num > maxs:
maxs = num

num = int(input("Type a number (or " + str(SENTINEL) + " to stop): "))

if mins != SENTINEL:
print("Maximum was", maxs)
print("Minimum was", mins)
```
7. Results of `boolean` expressions:

1. `True`
2. `True`
3. `False`
4. `True`
5. `True`
6. `False`
7. `False`
8. `True`
9. `True`
10. `True`
11. `True`
12. `False`
8. ```def is_vowel(c):
c = c.lower()  # case-insensitive
return c == "a" or c == "e" or c == "i" or c == "o" or c == "u"
```
or:
```def is_vowel(c):
return "aeiouAEIOU".find(c) >= 0
```
9. In this `is_prime` code the boolean flag isn't being used properly, because if the code finds a factor of the number, `prime` will be set to `False`, but on the next pass through the loop, if the next number isn't a factor, `prime` will be reset to `Tue` again. The following code fixes the problem:
```def is_prime(n):
prime = True
for i in range(2, n):
if n % i == 0:
prime = False
return prime
```
10. Improved version of `start_end_same` code using boolean zen:
```def start_end_same(string):
return string == string[-1]
```
11. Improved version of `has_pennies` code using Boolean zen:
```def has_pennies(cents):
return cents % 5 != 0
```
12. Output of `mystery` calls:

Call Value Returned
a. `mystery(3, 3)` `3`
b. `mystery(5, 3)` `1`
c. `mystery(2, 6)` `2`
d. `mystery(12, 18)` `6`
e. `mystery(30, 75)` `15`
13. The Zune code will get stuck in an infinite loop when the current date is the end of a leap year. On December 31 of a leap year, the `days` value will be 366, so code enters the `if is_leap_year` statement but does not enter the `if days > 366` statement. So the loop does not subtract any days and never terminates. It can be fixed by adding a boolean flag to the loop:
```days = get_total_days_since_1980()
year = 1980
stop = False
while days > 365 and not stop:   # subtract out years
if is_leap_year(year):
if days > 366:
days -= 366
year += 1
else:               # new code here
stop = True     # new code here
else:
days -= 365
year += 1
```
14. Negations of boolean expressions:
1. `not b`
2. `(x <= y) or (y <= z)`
3. `(x != y) and (x > z)`
4. `(x % 2 == 0) or not b`
5. `(x // 2 != 13) and not b and (z * 3 != 96)`
6. `(z >= x) or (z <= y and x < y)`
15. The age/GPA reading code should reprompt for a valid integer for the user's age and a valid real number for the user's GPA. If the user types a token of the wrong type, the line of input should be consumed and the user should be reprompted. The following code implements the corrected behavior:
```success = False
while not success:
age = input("Type your age: ")
try:
age = int(age)
success = True
except ValueError:
print("Not an integer; try again.")

success = False
while not success:
gpa = input("Type your GPA: ")
try:
gpa = float(gpa)
success = True
except ValueError:
print("Not a float; try again.")

print("age =", age, " GPA = ", gpa)
```
16. Write code that prompts for three integers, averages them, and prints the average; robust against invalid input:
```prompt = "Please enter a number: "
num1 = get_int(prompt)
num2 = get_int(prompt)
num3 = get_int(prompt)
average = (num1 + num2 + num3) / 3.0
print("Average:", average)
```
17. Point B
Point `y < x` `y == 0` `count > 0`
Point A SOMETIMES SOMETIMES NEVER
ALWAYS SOMETIMES SOMETIMES
Point C ALWAYS ALWAYS ALWAYS
Point D SOMETIMES SOMETIMES SOMETIMES
Point E NEVER SOMETIMES SOMETIMES
18. Point B
Point `n > b` `a > 1` `b > a`
Point A SOMETIMES SOMETIMES SOMETIMES
ALWAYS SOMETIMES SOMETIMES
Point C SOMETIMES ALWAYS ALWAYS
Point D SOMETIMES ALWAYS NEVER
Point E NEVER SOMETIMES SOMETIMES
19. Point `next == 0` `prev == 0` `next == prev`
Point A SOMETIMES ALWAYS SOMETIMES
Point B NEVER SOMETIMES SOMETIMES
Point C NEVER NEVER ALWAYS
Point D SOMETIMES NEVER SOMETIMES
Point E ALWAYS SOMETIMES SOMETIMES

## Chapter 6

1. A file is a named collection of information stored on a computer. We can read a file by opening it and then using the `read` or `readlines` method:

```with open("input.txt") as file:
```
2. ```with open("input.txt") as file:
```
3. The call to `split` returns:

c. `["welcome...to", "the", "matrix."]`
4. The call to `split` returns:

b. `["in", "fourteen-hundred", "92", "columbus", "sailed", "the", "ocean", "blue", ":)"]`
1. `"numbers.dat"` or `"C:/Users/yana/Documents/programs/numbers.dat"`
2. `"data/homework6/input.dat"` or `"C:/Users/yana/Documents/programs/data/homework6/input.dat"`
3. There is only one legal way to refer to this file: by its absolute path, `"C:/Users/yana/Documents/homework/data.txt"`
1. `"names.txt"` or `"/home/yana/Documents/hw6/names.txt"`
2. `"data/numbers.txt"` or `"/home/yana/Documents/hw6/data/numbers.txt"`
3. There is only one legal way to refer to this file: by its absolute path, `"/home/yana/download/saved.html"`
5. The following output would be produced:

```input: 6.7        This file has
input:         several input lines.
input:
input:   10 20         30   40
input:
input: test
6 total
```
6. Output produced if `readlines` and `split` are used:

```input: 6.7
input: This
input: file
input: has
input: several
input: input
input: lines.
input:
input: 10
input: 20
input: 30
input: 40
input:
input: test
14 total
```
7. Program that prints itself as output:

```def main():
with open("input.txt") as file:
for line in lines:
print(line.strip())

main()
```
8. Code that prompts the user for a file name and prints the contents of that file to the console as output:

```def print_entire_file():
file_name = input("Type a file name: ")
with open(file_name) as file:
for line in lines:
print(line.strip())
```
9. Program that takes as input lines of text and produces as output the same text inside a box:

```# precondition: no line in input is longer than width
def print_box(lines, width):
print_top_bottom(width)
for line in lines:
spaces = width - len(line.strip())
print("| " + line.strip() + (" " * spaces) + " |")
print_top_bottom(width)

def print_top_bottom(width):
print("+", end="")
for i in range(0, width + 2):
print("-", end="")
print("+")
```
10. Code to print the following four lines of text into a file named `message.txt`:

```with open("message.txt", "w") as my_file:
print("Testing,", file=my_file)
print("1, 2, 3.", file=my_file)
print("", file=my_file)
print("This is my output file.", file=my_file)
```
11. Code that repeatedly prompts the user for a file name until the user types the name of a file that exists on the system.

```import os.path

def get_file_name():
file_name = ""
while not os.path.isfile(file_name):
file_name = input("Type a file name: ")
return file_name
```
12. Code that uses `get_file_name` before calling `print_entire_file`:

```# reprompts until file name is valid
def print_entire_file_2():
file_name = get_file_name()
with open(file_name) as file:
for line in lines:
print(line.strip())
```

## Chapter 7

• First element: `numbers`
• Last element: `numbers` or `numbers[len(numbers) - 1]` or `numbers[-1]`
1. ```data = [27, 51, 33, -1, 101]
```
2. Code that stores all odd numbers between -6 and 38 into an array using a loop:

```odds =  * 22
for i in range(len(odds)):
odds[i] = i * 2 - 5
```
3. After the code is executed, the `numbers` list contains the following element values:

```[0, 4, 11, 0, 44, 0, 0, 2]
```
4. After the code is executed, the `data` list contains the following element values:

```[3, 3, 0, 0, 6, 9, 0, -18]
```
5. ```data = [7, -1, 13, 24, 6]
```
1. `letters[:2]`
2. `letters[3:4]`
3. `letters[3:]`
4. `letters[:3:-1]`
5. `letters[1::2]`
6. ```def maximum(data):
maxs = data
for i in range(1, len(data)):
if data[i] > maxs:
maxs = data[i]
return maxs
```
7. ```def average(a):
mean = 0.0
for i in range(0, len(a)):
mean += a[i]
return mean / len(a)
```
8. `data[3:3] = ["dark", "and"]`
9. `data = "IS"`
10. ```i = 0
while i < len(data):
if "a" in data[i]:
data.pop(i)
else:
i += 1
```
11. A list traversal is a sequential processing of each of an list's elements. Problems that can be solved in this manner include printing a list, comparing two lists for equality, and searching a list for a given value.

12. Code that uses a `for` loop to print each element of a list named `data`:

```for i in range(len(data)):
print("element [", i, "] is", data[i])
```
13. After the code is executed, the `list` array contains the following element values:

```[3, 24, 8, -6, 6, 1]
```
1. `[1, 2, 6, 8]`
2. `[10, 30, 40, 20, 60, 50]`
3. `[-4, 1, 25, 4, 16, 9, 64, 36, 49]`
1. `[20, 10, 20, 30, 30, 20]`
2. `[8, 7, 8, 2, 9, 7, 4, 4, 2, 8]`
3. `[33, 28, 33, -1, 3, 28, 17, 9, 33, 17, -1, 33]`
14. ```def all_less(list1, list2):
if len(list1) != len(list2):
return False
for i in range(len(list1)):
if list1[i] >= list2[i]:
return False
return True
```
15. After the code is executed, the `numbers` list contains the following element values:

```[20, 30, 40, 50, 60, 70, 80, 90, 100, 100]
```
16. After the code is executed, the `numbers` list contains the following element values:

```[10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
```
17. After the `mystery` function is executed, the list `a1` contains the following element values:

```[26, 19, 14, 11, 10]
```
18. After the `mystery2` function is executed, the list `numbers` contains the following element values:

```[7, 3, 1, 0, 25, 4, 18, -1, 5]
```
19. Results of calls to `mystery3` function:

1. `0`
2. `9`
3. `6`
4. `8`
5. `2`
20. ```def average_length(strings):
sums = 0
for i in range(len(strings)):
sums += len(strings[i])
return sums / len(strings)
```
21. ```def is_palindrome(lis):
for i in range(len(lis) // 2):
if lis[i] != lis[len(lis) - 1 - i]:
return False
return True
```
1. `[s.upper() for s in letters]`
2. `[s + s for s in letters]`
3. `[(s, s) for s in letters]`
22. Output of the program:

```2 [0, 0, 1, 0]
1 [0, 0, 1, 0]
3 [0, 0, 1, 1]
2 [0, 0, 1, 1]
```
23. Output of the program:

```2 [0, 1]
1 [0, 1]
1 [1, 2]
0 [1, 2]
```
24. ```def swap_pairs(lis):
for i in range(0, len(lis), 2):
swap(lis, i, i + 1)
```
25. The four errors are:
1. On line 2, you can't modify the value of a tuple by adding 1 to one of its elements.
2. On line 4, you can't call `append` on a tuple.
3. On line 6, you can't call `reverse` on a tuple.
4. On line 9, you can't call `clear` on a tuple.
26. ```def nearest_points(points):
min_dist = 0
for i in range(len(points)):
for j in range(i + 1, len(points)):
dist = distance(points[i], points[j])
if min_dist == 0 or dist < min_dist:
min_dist = dist
return min_dist

def distance(p1, p2):
dx = p2 - p1
dy = p2 - p1
return math.sqrt(dx * dx + dy * dy)
```
27. After the code is executed, the `numbers` list contains the following element values:

```[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
```
28. Loop to initialize the third row of `data` to store the numbers 1 through 7:

```for i in range(7):
data[i] = i + 1
```
29. Code that constructs a two-dimensional list of integers with 5 rows and 10 columns, filled with a multiplication table:

```table = []
for i in range(5):
table.append( * 10)
for i in range(5):
for j in range(10):
table[i][j] = i * j
```
30. Loop to copy the contents of second column into fifth column:

```for i in range(6):
matrix[i] = matrix[i]
```
31. After the `mystery2d` function is executed, the `numbers` list contains the following element values:

```[[4, 5, 6, 6], [5, 6, 7, 7], [6, 7, 8, 8]]
```
32. ```jagged = []
value = 1
for i in range(5):
jagged.append( * (i + 1))
for j in range(i + 1):
jagged[i][j] = value
value += 1
```
33. pixel list dimensions (TODO)
34. to_red_channel (TODO)

## Chapter 8

1. You can examine every element of a dictionary using a for-each loop. You can check whether a key is in the dictionary with the `in` keyword.

2. If you try to add a key/value pair to a dictionary and it already has a pair with that same key, the old pair is replaced by the new pair. If it already has a pair with the same value, but not with the same key, the new pair is added without removing the old pair.

3. You can loop over the keys of a dictionary in sorted order by passing the keys to the `sorted` function.

4. Code to declare a dictionary that associates people's names with their ages:

```ages = {}
ages["Stuart"] = 85
ages["Marty"] = 12
ages["Allison"] = 25
```

or:

```ages = {"Stuart": 85, "Marty": 12, "Allison": 25}
```
5. Keys and values contained in the dictionary after the code executes:

```{17: 'Steve', 34: 'Louann', 5: 'Moshe', 27: 'Donald', 2350: 'Orlando', 15: 'Moshe'}
```
6. Keys and values contained in the dictionary after the code executes:

```{132: 'OneThreeTwo', 8: 'Ocho', 9828: 'Ninety-eight18', 8650: 'Eighty-sixForty-one', 50: 'Fifty', 79: 'Seventy-nine'}
```
7. Output produced when the `mystery` method is passed each dictionary:

1. `{'one': 'un', 'four': 'quatre', 'deux': 'two', 'cinq': 'five', 'three': 'trois'}`
2. `{'computer': 'program', 'car': 'drive', 'board': 'skate'}`
3. `{'begin': 'ready', 'boy': 'girl', 'first': 'last', 'ebert': 'siskel', 'H': 'T'}`
4. `{'cotton': 'rain', 'light': 'tree', 'tree': 'violin', 'seed': 'tree'}`
8. Result returned when the `mystery` function is passed each pair of dictionaries:

1. `{'mumble': 'fire', 'baz': 'wind', 'bar': 'earth', 'foo': 'air'}`
2. `{'one': 'dos', 'five': 'quatro', 'three': 'tres'}`
3. `{'c': 'seven', 'g': 'seven', 'b': 'years', 'e': 'ago'}`
9. Result returned when the `mystery` function is passed each list:

1. `{1: , 2: [1, 1], 3: [], 4: , 34: [], 14: []}`
2. `{1: [1, 1, 1], 2: [1, 1], 4: [1, 1]}`
3. `{43: , 44: [], 45: [1, 1], 54: }`
10. Result returned when the `mystery` function is passed each dictionary:

1. `{3: {'and'}, 4: {'hello', 'world'}}`
2. `{1: {'banana', 'kiwi'}, 2: {'peach'}, 3: {'apple', 'nectarine'}}`
3. `{'the': {'is', 'has'}, 'and': {'the', 'and'}}`
11. start_letters TODO
12. dict_comprehensions TODO
13. You should use a set rather than a list if you wanted to avoid duplicates or wanted to be able to search the collection quickly.

14. You can examine every element of a set using a for-each loop.

15. You can check whether a value is contained in a set with the `in` keyword.

16. After the code executes, the set contains the following elements (in some order):

```{32, 18274, 18212, 9, 12, 29999, 9074}
```
17. After the code executes, the set contains the following elements (in some order):

```{4, 42, 11, 12, 84, 247, 94}
```
18. To do a union, use `set1 | set2` to create a new set with all items in both sets. To do an intersection, use `set1 & set2` to create a new set with only items in both of the sets.

19. To find all of the men who are not hungry and are old or poor or both: `(male - hungry) & (old | poor)`

20. Output produced when the `mystery` function is passed each list:
1. `{'jessica', 'amanda', 'helene'}`
2. `{'riley'}`
3. `{'charlie', 'phil', 'alex', 'roy', 'tyler'}`

## Chapter 9

1. Recursion is a technique where an algorithm is expressed in terms of itself. A recursive function differs from a regular function in that it contains one or more calls to itself within its body.

2. A base case is a situation where a recursive function does not need to make a recursive call to solve the problem. A recursive case is a situation where the recursive function does call itself. Recursive functions need both cases because the recursive case is called repeatedly until the base case is reached, stopping the chain of recursive calls.

3. Output produced by the `mystery1` function by each call:

1. `1`
2. `1, 2`
3. `1, 3`
4. `1, 2, 4`
5. `1, 2, 4, 8, 16`
6. `1, 3, 7, 15, 30`
7. `1, 3, 6, 12, 25, 50, 100`
4. Output produced by the `mystery2` function by each call:

1. `113`
2. `140, 70`
3. `168, 84, 42`
4. `120, 60, 30`
5. `160, 80, 40, 20, 10`
5. Output produced by the `mystery_x_y` function by each call:

1. `4`
2. `8, 4, 8`
3. `16, 8, 16`
4. `12, 8, 4, 8, 12`
5. `12, 9, 6, 3, 6, 9, 12`
6. Recursive version of `double_reverse` function:

```def double_reverse(s):
if len(s) > 0:
last = s[-1]
print(last, end="")
print(last, end="")
double_reverse(s[0:-1])
```
7. The version of the `pow` function shown does not have any base case, so the recursive calls will never stop. It can be fixed by adding a check for `y == 0` that does not make a recursive call.

8. The second version of the `pow` function is more efficient than the first because it requires fewer recursive calls. Both versions are recursive.

9. Value returned by the `mystery4` function for each call:

1. `6`
2. `4`
3. `7`
4. `0`
5. `1`
10. Value returned by the `mystery5` method for each call:

1. `57`
2. `1029`
3. `-74`
4. `2438`
5. `132483`
11. Recursive version of `factorial` function:

```def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n - 1)
```
12. The base case `if` statement has a bug: It should test for numbers less than 10, not greater. The following is the correct line:

```if n < 10:
```
13. When the parameters needed for recursion don't match those that make sense for the client to pass, use a function with the signature desired by the client and a helper function with the signature needed for the recursion.

14. The following version of the `fibonacci` code has improved efficiency:

```def fibonacci(n):
if n <= 2:
return 1
else:
return fibonacci2(n, 3, 1, 1)

def fibonacci2(n, i, prev, curr):
if n == i:
return prev + curr
else:
return fibonacci2(n, i + 1, curr, prev + curr)
```
15. A fractal is an image that is recursively constructed to contain smaller versions of itself. Recursive functions are useful when drawing fractal images because they can elegantly express the recursive nature of the images.

16. Code to create and draw a regular hexagon:

```def draw_hexagon(panel, x, y, size):
p1 = (x, y + size // 2)
p2 = (x + size // 3, y)
p3 = (x + 2 * size // 3, y)
p4 = (x + size, y + size // 2)
p5 = (x + 2 * size // 3, y + size)
p5 = (x + size // 3, y + size)
panel.fill_polygon(p1, p2, p3, p4, p5)
```
17. Recursion is an effective way to implement a backtracking algorithm because the memory of decisions and points to go back to are represented by the recursive call stack. The pattern of "choose, explore, un-choose is elegantly represented by recursive calls for each individual choice.

18. A decision tree is a description of the set of choices that can be made by a recursive backtracking function at any point in the algorithm.

19. Decision tree that would have resulted for Figure for paths to (1, 2) if the backtracking solution had explored NE first instead of last in the recursive `explore` function:

```start (0, 0)
|
+--- NE (1, 1)
|    |
|    +--- NE NE (2, 2)
|    |
|    +--- NE N (1, 2) - output
|    |
|    +--- NE E (2, 1)
|
+--- N (0, 1)
|    |
|    +--- N NE (1, 2) - output
|    |
|    +--- N N (0, 2)
|    |    |
|    |    +--- N N NE (1, 3)
|    |    |
|    |    +--- N N N (0, 3)
|    |    |
|    |    +--- N N E (1, 2) - output
|    |
|    +--- N E (1, 1)
|         |
|         +--- N E NE (2, 2)
|         |
|         +--- N E N (1, 2) - output
|         |
|         +--- N E E (2, 1)
|
+--- E (1, 0)
|
+--- E NE (2, 1)
|
+--- E N (1, 1)
|    |
|    +--- E N NE (2, 2)
|    |
|    +--- E N N (1, 2) - output
|    |
|    +--- E N E (2, 1)
|
+--- E E (2, 0)
```
20. If the solution had explored NE first instead of last, the solutions would have been printed in this order:

```moves: NE N
moves: N NE
moves: N N E
moves: N E N
moves: E N N
```
21. There are 64 entries at the second level of the full tree. There are 512 entries at the third level of the full tree.

22. If our 8 Queens algorithm tried every possible square on the board for placing each queen, there would be (64*63*62*61*60*59*58*57) = 178,462,987,637,760 entries are there at the 8th and final level of the full tree. Our algorithm avoids such a huge number of choices by only placing one queen in each column of the board.

23. The 8 Queens `explore` function stops once it finds one solution to the problem. This is because the code has the following lines around its recursive call:

```if explore(b, col + 1):
return True
```

The code could be modified so that it would find and output every solution to the problem by changing that code to the following:

```explore(b, col + 1)
```

And changing the base case to the following:

```if col > len(b):
print("One solution is as follows:")
b.print()
return True
```

## Chapter 10

1. You can perform a sequential search over the list using a loop, or you can sort the list using `sort` and then perform a binary search over it using `bisect.bisect_left`.

2. Closest value to the number of elements that the binary search algorithm will need to examine on a list of one million integers:

e. less than 1% (10,000 or fewer)
3. You should use binary search if the list is sorted. Otherwise you will have to use sequential search.

4. O(log N)

5. O(N)

6. O(N2)

7. O(N2)

8. Complexity classes of the given algorithms in terms of N:

1. O(N)
2. O(N2)
3. O(N)
4. O(N)
5. O(N)
6. O(1)
9. Complexity classes of the given statements:

1. O(N log N)
2. O(N2)
3. O(N2 log N)
4. O(N)
5. O(N^4)
6. O(N)
7. O(N!)
10. The runtime complexity of both sequential searches is O(N).

11. Binary search requires a sorted dataset because it uses the ordering to jump to the next index. If the elements are out of order, the search isn't guaranteed to find the target element.

12. A binary search of 60 elements examines at most 6 elements, because log2 60 (when rounded up) equals 6.

1. The algorithm will examine index 4 and will return 4.
2. The algorithm will examine indexes 4 and 6 and will return 6.
3. The algorithm will examine indexes 4, 6, and 7 and will return 7.
4. The algorithm will examine indexes 4, 2, 1, and 0 and will return 0.
13. The algorithm will examine indexes 4, 6, and 5 and will return -1. The algorithm doesn't work properly because the input array isn't sorted.

14. The binary search algorithm will examine the following indexes and return the following values for each search:

1. -5: examines 6, 2, 4, 3; returns -4
2. 0: examines 6; returns 6
3. 11: examines 6, 10, 8, 9; returns -10
4. -100: examines 6, 2, 0; returns -1
15. After a single pass of the selection sort algorithm (a single swap), the state of the list is:

d. `[-4, 17, 3, 94, 46, 8, 29, 12]`
16. All steps of selection sort algorithm:

1. ```[29, 17, 3, 94, 46, 8, -4, 12]
[-4, 17, 3, 94, 46, 8, 29, 12]
[-4, 3, 17, 94, 46, 8, 29, 12]
[-4, 3, 8, 94, 46, 17, 29, 12]
[-4, 3, 8, 12, 46, 17, 29, 94]
[-4, 3, 8, 12, 17, 46, 29, 94]
[-4, 3, 8, 12, 17, 29, 46, 94]
```
2. ```[33, 14, 3, 95, 47, 9, -42, 13]
[-42, 14, 3, 95, 47, 9, 33, 13]
[-42, 3, 14, 95, 47, 9, 33, 13]
[-42, 3, 9, 95, 47, 14, 33, 13]
[-42, 3, 9, 13, 47, 14, 33, 95]
[-42, 3, 9, 13, 14, 47, 33, 95]
[-42, 3, 9, 13, 14, 33, 47, 95]
```
3. ```[7, 1, 6, 12, -3, 8, 4, 21, 2, 30, -1, 9]
[-3, 1, 6, 12, 7, 8, 4, 21, 2, 30, -1, 9]
[-3, -1, 6, 12, 7, 8, 4, 21, 2, 30, 1, 9]
[-3, -1, 1, 12, 7, 8, 4, 21, 2, 30, 6, 9]
[-3, -1, 1, 2, 7, 8, 4, 21, 12, 30, 6, 9]
[-3, -1, 1, 2, 4, 8, 7, 21, 12, 30, 6, 9]
[-3, -1, 1, 2, 4, 6, 7, 21, 12, 30, 8, 9]
[-3, -1, 1, 2, 4, 6, 7, 21, 12, 30, 8, 9]
[-3, -1, 1, 2, 4, 6, 7, 8, 12, 30, 21, 9]
[-3, -1, 1, 2, 4, 6, 7, 8, 9, 30, 21, 12]
[-3, -1, 1, 2, 4, 6, 7, 8, 9, 12, 21, 30]
```
4. ```[6, 7, 4, 8, 11, 1, 10, 3, 5, 9]
[1, 7, 4, 8, 11, 6, 10, 3, 5, 9]
[1, 3, 4, 8, 11, 6, 10, 7, 5, 9]
[1, 3, 4, 8, 11, 6, 10, 7, 5, 9]
[1, 3, 4, 5, 11, 6, 10, 7, 8, 9]
[1, 3, 4, 5, 6, 11, 10, 7, 8, 9]
[1, 3, 4, 5, 6, 7, 10, 11, 8, 9]
[1, 3, 4, 5, 6, 7, 8, 11, 10, 9]
[1, 3, 4, 5, 6, 7, 8, 9, 10, 11]
```
17. A merge sort of 32 elements will generate 63 total calls to `merge_sort` and will perform the `merge` operation 31 times.

1. State of the elements after five passes of the outermost loop of selection sort have occurred:

```[1, 2, 3, 4, 5, 11, 9, 7, 8, 10]
```
2. Trace of merge sort algorithm:

```[7,   2,   8,   4,   1,   11,   9,   5,   3,   10]
[7,   2,   8,   4,   1], [11,   9,   5,   3,   10]
[7,   2], [8,   4,   1], [11,   9], [5,   3,   10]
, , , [4,   1], , , , [3,   10]
, ,                 , 
, [1,   4],            , [3,   10]
[2,   7], [1,   4,   8], [9,   11], [3,   5,   10]
[1,   2,   4,   7,   8], [3,    5,   9,  10,   11]
[1,   2,   3,   4,   5,   7,    8,   9,  10,   11]
```
1. State of the elements after five passes of the outermost loop of selection sort have occurred:

```[-3, -1, 1, 2, 4, 8, 7, 21, 12, 30, 6, 9]
```
2. Trace of merge sort algorithm:

```[7,   1,   6,   12,   -3,   8,    4,   21,   2,   30,   -1,   9]
[7,   1,   6,   12,   -3,   8],  [4,   21,   2,   30,   -1,   9]
[7,   1,   6], [12,   -3,   8],  [4,   21,   2], [30,   -1,   9]
, [1,   6], , [-3,   8],  , [21,   2], , [-1,   9]
, ,       [-3], ,       , ,       [-1], 
, [1,   6], , [-3,   8],  , [2,   21], , [-1,   9]
[1,   6,   7], [-3,    8,  12],  [2,   4,   21], [-1,    9,  30]
[-3,  1,   6,    7,    8,  12], [-1,   2,    4,    9,   21,  30]
[-3, -1,   1,    2,    4,   6,    7,   8,    9,   12,   21,  30]
```
18. The following statement about sorting and big-Oh is true:

b. Merge sort achieves an O(N log N) runtime by dividing the list in half at each step and then recursively sorting and merging the halves back together.
19. Traces of merge sort algorithm:

1. ```[29, 17, 3, 94, 46, 8, -4, 12]
[29, 17, 3, 94], [46, 8, -4, 12]
[29, 17], [3, 94], [46, 8], [-4, 12]
, , , , , , [-4], 
[17, 29], [3, 94], [8, 46], [-4, 12]
[3, 17, 29, 94], [-4, 8, 12, 46]
[-4, 3, 8, 12, 17, 29, 46, 94]
```
2. ```[6, 5, 3, 7, 1, 8, 4, 2]
[6, 5, 3, 7], [1, 8, 4, 2]
[6, 5], [3, 7], [1, 8], [4, 2]
, , , , , , , 
[5, 6], [3, 7], [1, 8], [2, 4]
[3, 5, 6, 7], [1, 2, 4, 8]
[1, 2, 3, 4, 5, 6, 7, 8]
```
3. ```[33, 14, 3, 95, 47, 9, -42, 13]
[33, 14, 3, 95], [47, 9, -42, 13]
[33, 14], [3, 95], [47, 9], [-42, 13]
, , , , , , [-42], 
[14, 33], [3, 95], [9, 47], [-42, 13]
[14, 33], [3, 95], [9, 47], [-42, 13]
[3, 14, 33, 95], [-42, 9, 13, 47]
[-42, 3, 9, 13, 14, 33, 47, 95]
```

## Chapter 11

1. Procedural programming treats a program as a sequence of actions or commands to perform. Object-oriented programming looks at a program as a group of interacting entities named objects that each keep track of related data and behavior.

2. An object is an entity that encapsulates data and behavior that operates on the data. A class is the blueprint for a type of object, specifying what data and behavior the object will have and how to construct it.

3. Output of the program:

```14 14
7 9 14 2
18 18
7 9 14 18
```
4. The state of a `Calculator` object might include the number that has just been computed, as well as another number that is currently being input. A more complex `Calculator` object might also include a memory feature that stores an additional value. The behavior of a `Calculator` object might include methods to add, subtract, multiply, divide, and perhaps carryout other math operations (such as exponentiation, logarithms, and trigonometric functions like sine and cosine).

5. An attribute is a variable that exists inside of an object. A parameter is a variable inside a method whose value is passed in from outside. Attributes have different syntax because they are declared at the top of a class and not in a method's header. An attribute's scope is throughout the class, while a parameter's scope is limited to the method.

6. `Name` class that represents a person's name:

```# A Name object represents a name such as "John Q. Public".
# This version contains only data attributes and a constructor.
class Name:
def __init__(self, first, middle, last):
self.first_name = first
self.middle_initial = middle
self.last_name = last
```
7. An accessor provides the client access to some data in the object, while a mutator lets the client change the object's state in some way. Accessors' names often begin with "get" or "is", while mutators' names often begin with "set".

8. Correct syntax for calling `compute_interest` method on a `BankAccount` object:

d. `result = acct.compute_interest(42)`
9. `Name` class with two methods:

```# A Name object represents a name such as "John Q. Public".
# This version adds the methods get_normal_order and get_reverse_order.
class Name:
def __init__(self, first, middle, last):
self.first_name = first
self.middle_initial = middle
self.last_name = last

# The name in normal order such as "John Q. Public".
def get_normal_order(self):
return self.first_name + " " + self.middle_initial + ". " + self.last_name

# The name in reverse order such as "Public, John Q.".
def get_reverse_order(self):
return self.last_name + ", " + self.first_name + " " + self.middle_initial + "."
```
10. To make the objects of your class printable, define a `__str__` method in it.

11. The `print` statement is equivalent to the following:

c. `print(d1.__str__())`
12. `__str__` method for `Name` class:

```# Returns a string representation of this Name, such as "John Q. Public".
def __str__(self):
return self.first_name + " " + self.middle_initial + ". " + self.last_name
```
or:
```# Returns a string representation of this Name, such as "John Q. Public".
def __str__(self):
return self.get_normal_order()
```
13. Abstraction is the ability to focus on a problem at a high level without worrying about the minor details. Objects provide abstraction by giving us more powerful pieces of data that have sophisticated behavior without having to manage and manipulate the data directly.

14. To access private attributes, create properties that return their values. For example, add a `name` property to access the `_name` data attribute of an object. You can also write accessor methods that return data from the object.

15. Encapsulated version of `Name` class:

```# A Name object represents a name such as "John Q. Public".
# This version is encapsulated with underscored attributes and properties.
class Name:
# Initializes a new Name with the given values.
def __init__(self, first, middle, last):
self._first = first
self._middle = middle
self._last = last

# Returns the person's first name.
@property
def first_name(self):
return self._first

# Returns the person's middle initial.
@property
def middle_initial(self):
return self._middle

# Returns the person's last name.
@property
def last_name(self):
return self._last

# The name in normal order such as "John Q. Public"
def get_normal_order(self):
return self._first + " " + self._middle + ". " + self._last

# The name in reverse order such as "Public, John Q.".
def get_reverse_order(self):
return self._last + ", " + self._first + " " + self._middle + "."

# The name in normal order such as "John Q. Public"
def __str__(self):
return self.get_normal_order()
```
16. Property setters for `Name` class:

```class Name:
...

# Sets the first name to the given value.
@first_name.setter
def first_name(self, value):
self._first = value

# Sets the middle initial to the given value.
@middle_initial.setter
def middle_initial(self, value):
self._middle = value

# Sets the last name to the given value.
@last_name.setter
def last_name(self, value):
self._last = value
```
17. Encapsulation allows you to change a class's internal implementation without changing its external view to clients. When a class is encapsulated clients should not directly access its attributes, so changing those fields will not disturb client behavior as long as the external view (method behavior) is consistent.

18. Cohesion is the concept of how well a class's contents go together. You can tell that a class is cohesive when each of its attributes stores important state related to the object and each method interacts with that state in some way to produce useful behavior.

19. We did not place console I/O code into our `Stock` class because doing so would force clients to use those exact I/O messages. By keeping I/O code out of `Stock`, we kept it independent from its clients.

20. Accessor methods for `Stock` class:

```# Returns this Stock's symbol value.
def get_symbol(self):
return self._symbol

# Returns this Stock's total number of shares purchased.
def get_total_shares(self):
return self._total_shares

# Returns this Stock's total cost for all shares.
def get_total_cost(self):
return self._total_cost
```

## Chapter 12

1. Because functional programming focuses so much on individual functions, the community of programmers who use functional programming regularly have concluded that side effects should be avoided when possible. Functions without side effects are easy to reason about, reuse, combine, and parallelize.

2. Calling `print` is considered a side effect because it produces a noticeable outcome, namely printing output to the console. So you can detect whether a given function was called or not by looking for output. This doesn't mean that printing output is a bad thing, merely that it is a side effect.

3. The function's side effect is that it modifies the list that was passed in. It could be changed to remove side effects by having it return the new list state rather than changing the existing list.

```# Returns a new list whose values are twice as large as
# the values of all elements in the given list.
def double_all(lis):
result =  * len(lis)
for i in range(len(lis)):
result[i] = 2 * lis[i]
return result
```
4. ```lambda num: num * num
```
5. ```lambda a, b: max(a, b)
```
6. ```lambda first, last: last + ", " + first
```
7. ```[10, 28, 33, 28, 49, 56, 49]
```

8. ```list(filter(lambda num: num >= 0, numbers))
```
9. A bound variable is inside the lambda, typically one of its parameters. A free variable is a variable referred to in the lambda's code that is declared outside the lambda and enclosed into its closure.

10. The free variable is `a`, and the bound variables are `b` (the second one) and `c`.