Learn Programming: Python - Remake

Learn Programming: Python - Remake

30 ratings
Exercise Break Guide
By niemasd
This guide will provide explanations for all "Exercise Breaks" in the game.
   
Award
Favorite
Favorited
Unfavorite
Introduction
I tried to make this guide as thorough as possible, but if you're still confused even after reading an explanation here (or have any follow-up questions), please feel free to create a new thread in the "Discussions" section! :-)

When you get stuck, I also highly recommend utilizing Python Tutor[pythontutor.com], which is an interactive online code visualization environment. Essentially, you can type in any Python code snippet, and it will run it line-by-line and visualize everything that's happening. It's a great tool to help you trace through code by hand.
Chapter 1.3.7
  • Option (a) is an invalid variable declaration because `None` is a reserved Python keyword (Python variable names cannot be equal to reserved Python keywords).
  • Option (b) is a valid variable declaration.
  • Option (c) is an invalid variable declaration because it begins with a number (Python variable names cannot begin with a number, though they can include numbers).
  • Option (d) is a valid variable declaration.
  • Option (e) is a valid variable declaration.
Chapter 1.4.3
Here is a depiction of the string "Programming is fun!" that is labeled with the indices (where _ denotes a space character):
Index: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Letter: | P | r | o | g | r | a | m | m | i | n | g | _ | i | s | _ | f | u | n | ! |
The question is asking about the following syntax:
res[5]
This syntax accesses index 5 of the string. As can be seen, the character at index 5 is a.
Chapter 1.4.4
Here is a depiction of the string "Programming is fun!" that is labeled with the indices (where _ denotes a space character):
Index: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Letter: | P | r | o | g | r | a | m | m | i | n | g | _ | i | s | _ | f | u | n | ! |
The question is asking about the following syntax:
res[1:5]
This syntax accesses the substring starting at index 1 (remember that Python start indices are inclusive) and ending just before index 5 (remember that Python end indices are exclusive). As can be seen, the substring starting at index 1 and ending just before index 5 (so including all the characters up to and including index 4) is the string rogr.
Chapter 1.4.8
Here is a depiction of the string "12 is > than 1." that is labeled with the indices (where _ denotes a space character):
Index: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Letter: | 1 | 2 | _ | i | s | _ | > | _ | t | h | a | n | _ | 1 | . |
The question is asking about the following syntax:
res[-6]
Negative indices access from the end, where an index of -1 means "the last character of the string", an index of -2 means "the second to last character of the string", etc. Therefore, an index of -6 means "the 6th character from the end". As can be seen in the above visualization, this corresponds to index 9, which contains the character h.
Chapter 1.4.9
Here is a depiction of the string "12 is > than 1." that is labeled with the indices (where _ denotes a space character):
Index: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Letter: | 1 | 2 | _ | i | s | _ | > | _ | t | h | a | n | _ | 1 | . |
The question is asking about the following syntax:
res[-5:-1]
This syntax accesses the substring starting at index -5 (remember that Python start indices are inclusive) and ending just before index -1 (remember that Python end indices are exclusive). As can be seen, the substring starting at index -5 (i.e., the 5th character from the end, which corresponds to index 10) and ending just before index -1 (so including all the characters up to and including index -2, i.e., the 2nd character from the end, which corresponds to index 13) is the string an 1.
Chapter 1.5.5
The question is asking about the following command:
print("The\n logs\n wo\n't chop themselves", end="!")
Each newline character (\n) moves the printing to the next line, and we are specifying that we want to end the print statement with an exclamation point (!) instead of the default of a newline character. Therefore, the following will get printed by this code:
The logs wo 't chop themselves!
As can be seen, 4 lines get printed.
Chapter 1.6.4
The question is asking about the following code snippet:
foo = 11 bar = 11 * 2 baz = 11 ** 2 + 7 foobar = foo + bar qup = baz - 20 + foobar ultimate = (foo * bar) + (foo ** 2) - 2
  1. We create a variable called foo that has a value of 11
  2. We create a variable called bar that has a value of 11 * 2
    • 11 * 2 means "11 times 2", which is 22
  3. We create a variable called baz that has a value of 11 ** 2 + 7
    • The exponentiation operator (**) has a higher operator precedence than the addition operator (+), so we evaluate 11 ** 2 first, which means "11 to the power of 2", which is 121
    • Now, we plug that in: 11 ** 2 + 7 becomes 121 + 7, which is 128
  4. We create a variable called foobar that has a value of foo + bar
    • foo has a value of 11, and bar has a value of 22, so we plug them in: foo + bar becomes 11 + 22, which is 33
  5. We create a variable called qup that has a value of baz - 20 + foobar
    • baz has a value of 128, and foobar has a value of 33, so we plug them in: baz - 20 + foobar becomes 128 - 20 + 33
    • The subtraction operator (-) and the addition operator (+) have the same operator precedence, so they are evaluated from left to right: 128 - 20 + 33 = 108 + 33, which is 141
  6. We create a variable called ultimate that has a value of (foo * bar) + (foo ** 2) - 2
    • foo has a value of 11, and bar has a value of 22, so we plug them in: (foo * bar) + (foo ** 2) - 2 becomes (11 * 22) + (11 ** 2) - 2
    • Parentheses are evaluated first: (11 * 22) means "11 times 22", which is 242, and (11 ** 2) means "11 to the power of 2", which is 121
    • Now, we plug them in: (11 * 22) + (11 ** 2) - 2 becomes 242 + 121 - 2
    • The addition operator (+) and the subtraction operator (-) have the same operator precedence, so they are evaluated from left to right: 242 + 121 - 2 = 363 - 2, which is 361
Note that the parentheses in the last line are actually not necessary because the multiplication operator (*) and the exponentiation operator (**) both have higher precedence than the addition (+) and subtraction (-) operators.
Chapter 1.6.6
The question is asking about the following code snippet:
kax = 100 mar = kax // 7 rep = mar % 5 / float(2) bat = kax / (rep + 1)
  1. We create a variable called kax that has a value of 100
  2. We create a variable called mar that has a value of kax // 7
    • kax has a value of 100, so we plug it in: kax // 7 becomes 100 // 7
    • 100 // 7 means "100 integer-divided by 7" (recall that "integer division" means that we throw away the remainder by rounding down)
    • Normally, "100 divided by 7" would be 14.2857..., but with integer division, we round down to 14
  3. We create a variable called rep that has a value of mar % 5 / float(2)
    • mar has a value of 14, so we plug it in: 14 % 5 / float(2)
    • float(2) can just be thought of as floating-point 2 (e.g. 2.0), so let's plug it in to clean things up: 14 % 5 / 2.0
    • The modulo (remainder) operator (%) and the division operator (/) have the same operator precedence, so they are evaluated from left to right: 14 % 5 / float(2) = 4 / 2.0 = 2.0
  4. We create a variable called bat that has a value of kax / (rep + 1)
    • kax has a value of 100, and rep has a value of 2.0, so we plug them in: 100 / (2.0 + 1)
    • Parentheses are evaluated first: (2.0 + 1) means "2.0 plus 1", and because we have an arithmetic operation between a float (2.0) and an int (1), the int gets upgraded (so the 1 becomes 1.0), resulting in 2.0 + 1.0 = 3.0 (a float)
    • Now, we plug it in: 100 / (2.0 + 1) = 100 / 3.0, which means "100 divided by 3.0", and because we have an arithmetic operation between an int (100) and a float (3.0), the int gets upgraded (so the 100 becomes 100.0), resulting in 100.0 / 3.0 = 33.333...
Chapter 1.7.4
The question is asking you to write any single-line comment. Remember that all single-line comments begin with a # symbol. Thus, you can write literally anything, as long as it starts with a # symbol. The question provides a code snippet that you can use as inspiration:
print(message)
A reasonable single-line comment for that command would be the following:
# Print the message
Chapter 2.2.8
The question is asking about the following code snippet:
val not in "glass table" or val != "tab"
Let's plug the value of val into the logical expression for each of the answer responses:
  • Option (a): "la" not in "glass table" or "la" != "tab"
    • "la" not in "glass table" evaluates to False because "la" does show up as a substring of "glass table"
    • "la" != "tab" evaluates to True because "la" and "tab" are not equal
    • Plug them in, and you get False or True, which evaluates to True
  • Option (b): "3" not in "glass table" or "3" != "tab"
    • "3" not in "glass table" evaluates to True because "3" does not show up as a substring of "glass table"
    • "3" != "tab" evaluates to True because "3" and "tab" are not equal
    • Plug them in, and you get True or True, which evaluates to True
  • Option (c): "tab" not in "glass table" or "tab" != "tab"
    • "tab" not in "glass table" evaluates to False because "tab" does show up as a substring of "glass table"
    • "tab" != "tab" evaluates to False because "tab" and "tab" are equal
    • Plug them in, and you get False or False, which evaluates to False
  • Option (d): "foof" not in "glass table" or "foof" != "tab"
    • "foof" not in "glass table" evaluates to True because "foof" does not show up as a substring of "glass table"
    • "foof" != "tab" evaluates to True because "foof" and "tab" are not equal
    • Plug them in, and you get True or True, which evaluates to True
Chapter 2.2.9
The question is asking about the following code snippet:
a == 12 or b != 5 and c <= 10
Remember that logical `and` has higher precedence than logical `or`, so the code snippet above is equivalent to the following:
a == 12 or (b != 5 and c <= 10)
We want to determine potential values of a, b, and c, that will definitely make this expression evaluate to False.

Recall that the only way for logical or to evaluate to False is if both sides are False (i.e., False or False). Therefore, a == 12 must evaluate to False, and (b != 5 and c <= 10) needs to also evaluate to False.

Recall that logical and evaluates to False if either side (or both) is False (i.e., True and False, False and True, False and False). Therefore, for b != 5 and c <= 10 to evaluate to False, either b != 5 needs to evaluate to False, or c <= 10 needs to evaluate to False (or both).

Thus, for the expression to evaluate to False overall, a must not equal 12, and either b must equal 5 or c must be greater than 10.

Let's consider each of the answer responses (I'll keep the parentheses for clarity):
  • Option (a): a = 12, b = any positive int, c = any positive int
    • If we plug in a, we get 12 == 12 or (b != 5 and c <= 10), which is equivalent to True or (b != 5 and c <= 10)
    • Remember that True or True and True or False both evaluate to True, so the expression will always evaluate to True
    • Therefore, this option will definitely not evaluate to False
  • Option (b): a != 12, b = any positive int, c = any positive int
    • Because a is definitely not 12, the expression a == 12 will always evaluate to False
    • If we plug that in, we get False or (b != 5 and c <= 10). The only way for this to evaluate to True is if the expression b != 5 and c <= 10 evaluates to True
    • However, b and c can both be any positive int, so if b happens to be any int other than 5, or if c happens to be any int between 1 and 9, the expression would evaluate to True
    • Therefore, this option won't definitely evaluate to False (i.e., it might evaluate to True)
  • Option (c): a = any positive int, b = 5, c = any positive int
    • a can be any positive int, so if it happens to be 12, the expression a == 12 would evaluate to True
    • Therefore, this option won't definitely evaluate to False (i.e., it might evaluate to True)
  • Option (d): a = any positive int, b = any positive int, c = 100
    • a can be any positive int, so if it happens to be 12, the expression a == 12 would evaluate to True
    • Therefore, this option won't definitely evaluate to False (i.e., it might evaluate to True)
  • Option (e): a != 12, b = any positive int, c = 12
    • Because a is definitely not 12, the expression a == 12 will always evaluate to False
    • Because c is 12, the expression c <= 10 will always evaluate to False
    • If we plug those in, we get False or (b != 5 and False)
    • No matter what value we pick for b, this will definitely evaluate to False
Chapter 2.2.11
The question is asking about the following code snippet:
a and not (b or a)
Recall that logical not has higher precedence than logical and. Let's plug the values of a and b into the logical expression for each of the first 4 answer responses:
  • Option (a): False and not (False or False)
    • Parentheses first: False or False is False; plug it in: False and not False
    • not False is True; plug it in: False and True is False
  • Option (b): False and not (True or False)
    • Parentheses first: True or False is True; plug it in: False and not True
    • not True is False; plug it in: False and False is False
  • Option (c): True and not (False or True)
    • Parentheses first: False or True is True; plug it in: True and not True
    • not True is False; plug it in: True and False is False
  • Option (d): True and not (True or True)
    • Parentheses first: True or True is True; plug it in: True and not True
    • not True is False; plug it in: True and False is False
Therefore, the expression can never evaluate to True.
Chapter 2.3.2
The question is asking about the following code snippet:
ans = "My name is " age = 20 if age >= 20: ans = ans + "Mr. " ans = ans + "Slim Shady."
  1. We create a variable called ans that has a value of "My name is"
  2. We create a variable called age that has a value of 20
  3. We check if age >= 20
    • age has a value of 20, so we plug it in: age >= 20 becomes 20 >= 20, which is True
    • The if-statement condition is True, so we enter the body of the if-statement
    • ans has a value of "My name is ", so ans + "Mr. " is equivalent to "My name is " + Mr. ", which is a string concatenation that results in the string "My name is Mr. "
    • We plug it in: ans = "My name is Mr. " is an assignment operation, so we update ans to now have the value "My name is Mr. "
  4. Back outside of the if-statement, we now run ans = ans + "Slim Shady."
    • ans has a value of "My name is Mr. ", which we plug in: ans + "Slim Shady." evaluates to the string "My name is Mr. Slim Shady."
    • We plug it in: ans = "My name is Mr. Slim Shady." is an assignment operation, so we update ans to now have the value "My name is Mr. Slim Shady"
Chapter 2.3.5
The question is asking about the following code snippet:
num = 41 if num % 2 == 0: print("even") elif num % 2 == 1: print("odd") else: print("er, what")
The variable num has a value of 41, so the expression num % 2 becomes 41 % 2, which evaluates to 1 (because 41 divided by 2 has a remainder of 1).
  • We first check the if-statement condition: num % 2 == 0 becomes 1 == 0, which evaluates to False, so we don't enter the if-statement
  • We move to the elif-statement and check its condition: num % 2 == 1 becomes 1 == 1, which evaluates to True, so we enter the elif-statement
  • Inside the elif-statement, we print "odd"
  • Because we entered the elif-statement, we skip the else-statement
Chapter 2.4.2
Recall the possible outcomes of the logical expression x and y:
  • True and True evaluates to True
  • True and False evaluates to False
  • False and True evaluates to False
  • False and False evaluates to False
As can be seen, in the expression x and y, if x is False, the overall expression will evaluate to False regardless of the value of y. Further, if y is False, the overall expression will evaluate to False regardless of the value of x. Therefore, if either is False, the overall expression will be False.
Chapter 2.4.3
Recall the possible outcomes of the logical expression x or y:
  • True or True evaluates to True
  • True or False evaluates to True
  • False or True evaluates to True
  • False or False evaluates to False
As can be seen, in the expression x or y, if x is True, the overall expression will evaluate to True regardless of the value of y. Further, if y is True, the overall expression will evaluate to True regardless of the value of x. Therefore, if either is True, the overall expression will be True.
Chapter 3.2.3
The question is asking about the following code snippet:
x = 4 while x % 2 == 0 or x % 13 == 0: print("hello") x = 3*x + 1
For clarity, let's add some parentheses to the while-loop condition (though they are not required due to operator precedence):
x = 4 while (x % 2 == 0) or (x % 13 == 0): print("hello") x = 3*x + 1
Note that the while-loop condition is a logical expression with or, meaning it will be True if either side of the or is True.
  1. We create a variable called x that has a value of 4
  2. Check the while-loop condition: (4 % 2 == 0) or (2 % 13 == 0) becomes True or False which is True, so we enter the body of the while-loop
  3. We print "hello" for the first time
  4. We update the value of x to be 3*x + 1, which is 3*4 + 1, which is 13
  5. Check the while-loop condition: (13 % 2 == 0) or (13 % 13 == 0) becomes False or True which is True, so we enter the body of the while-loop
  6. We print "hello" for the second time
  7. We update the value of x to be 3*x + 1, which is 3*13 + 1, which is 40
  8. Check the while-loop condition: (40 % 2 == 0) or (40 % 13 == 0) becomes True or False which is True, so we enter the body of the while-loop
  9. We print "hello" for the third time
  10. We update the value of x to be 3*x + 1, which is 3*40 + 1, which is 121
  11. Check the while-loop condition: (121 % 2 == 0) or (121 % 13 == 0) becomes False or False which is False, so we exit the while-loop
Chapter 3.4.2
The question is asking about the following code snippet:
text = "alphabet" i = 0 while i <= 5: if text[i] == "h": print("pla") break print(text[i], end="") i += 1
  1. We create a variable called text that has a value of "alphabet"
  2. We create a variable called i that has a value of 0
  3. Check the while-loop condition: i has a value of 0, so 0 <= 5 is True, so we enter the body of the while-loop
  4. Check the if-statement condition: i has a value of 0, so text[i] == "h" is text[0] == "h", which is "a" == "h", which is False, so we don't enter the body if-statement
  5. i has a value of 0, so print(text[i], end="") is print(text[0], end=""), which is print("a", end=""), meaning we print "a" but don't move to a new line
  6. We execute i += 1, which increments i from 0 to 1
  7. Check the while-loop condition: i has a value of 1, so 1 <= 5 is True, so we enter the body of the while-loop
  8. Check the if-statement condition: i has a value of 1, so text[i] == "h" is text[1] == "h", which is "l" == "h", which is False, so we don't enter the body if-statement
  9. i has a value of 1, so print(text[i], end="") is print(text[1], end=""), which is print("l", end=""), meaning we print "l" but don't move to a new line
  10. We execute i += 1, which increments i from 1 to 2
  11. Check the while-loop condition: i has a value of 2, so 2 <= 5 is True, so we enter the body of the while-loop
  12. Check the if-statement condition: i has a value of 2, so text[i] == "h" is text[2] == "h", which is "p" == "h", which is False, so we don't enter the body if-statement
  13. i has a value of 2, so print(text[i], end="") is print(text[2], end=""), which is print("p", end=""), meaning we print "p" but don't move to a new line
  14. We execute i += 1, which increments i from 2 to 3
  15. Check the while-loop condition: i has a value of 3, so 3 <= 5 is True, so we enter the body of the while-loop
  16. Check the if-statement condition: i has a value of 3, so text[i] == "h" is text[3] == "h", which is "h" == "h", which is True, so we enter the body if-statement
  17. We execute print("pla"), meaning we print "pla" and move to a new line
  18. We hit a break, so we immediately break out of our while-loop
Thus, overall, we printed alppla.
Chapter 3.4.5
The question is asking about the following code snippet:
text = "alphabet" i = 0 while i <= 5: if text[i] == "h": print("pla", end=",") i += 1 continue print(text[i], end="") i += 1
  1. We create a variable called text that has a value of "alphabet"
  2. We create a variable called i that has a value of 0
  3. Check the while-loop condition: i has a value of 0, so 0 <= 5 is True, so we enter the body of the while-loop
  4. Check the if-statement condition: i has a value of 0, so text[i] == "h" is text[0] == "h", which is "a" == "h", which is False, so we don't enter the body if-statement
  5. i has a value of 0, so print(text[i], end="") is print(text[0], end=""), which is print("a", end=""), meaning we print "a" but don't move to a new line
  6. We execute i += 1, which increments i from 0 to 1
  7. Check the while-loop condition: i has a value of 1, so 1 <= 5 is True, so we enter the body of the while-loop
  8. Check the if-statement condition: i has a value of 1, so text[i] == "h" is text[1] == "h", which is "l" == "h", which is False, so we don't enter the body if-statement
  9. i has a value of 1, so print(text[i], end="") is print(text[1], end=""), which is print("l", end=""), meaning we print "l" but don't move to a new line
  10. We execute i += 1, which increments i from 1 to 2
  11. Check the while-loop condition: i has a value of 2, so 2 <= 5 is True, so we enter the body of the while-loop
  12. Check the if-statement condition: i has a value of 2, so text[i] == "h" is text[2] == "h", which is "p" == "h", which is False, so we don't enter the body if-statement
  13. i has a value of 2, so print(text[i], end="") is print(text[2], end=""), which is print("p", end=""), meaning we print "p" but don't move to a new line
  14. We execute i += 1, which increments i from 2 to 3
  15. Check the while-loop condition: i has a value of 3, so 3 <= 5 is True, so we enter the body of the while-loop
  16. Check the if-statement condition: i has a value of 3, so text[i] == "h" is text[3] == "h", which is "h" == "h", which is True, so we enter the body if-statement
  17. We execute print("pla",end=","), meaning we print "pla," and don't move to a new line
  18. We execute i += 1, which increments i from 3 to 4
  19. We hit a continue, so we immediately jump to the next iteration of our while-loop
  20. Check the while-loop condition: i has a value of 4, so 4 <= 5 is True, so we enter the body of the while-loop
  21. Check the if-statement condition: i has a value of 4, so text[i] == "h" is text[4] == "h", which is "a" == "h", which is False, so we don't enter the body if-statement
  22. i has a value of 4, so print(text[i], end="") is print(text[4], end=""), which is print("a", end=""), meaning we print "a" but don't move to a new line
  23. We execute i += 1, which increments i from 4 to 5
  24. Check the while-loop condition: i has a value of 5, so 5 <= 5 is True, so we enter the body of the while-loop
  25. Check the if-statement condition: i has a value of 5, so text[i] == "h" is text[5] == "h", which is "b" == "h", which is False, so we don't enter the body if-statement
  26. i has a value of 5, so print(text[i], end="") is print(text[5], end=""), which is print("b", end=""), meaning we print "b" but don't move to a new line
  27. We execute i += 1, which increments i from 5 to 6
  28. Check the while-loop condition: i has a value of 6, so 6 <= 5 is False, so we don't enter the body of the while-loop
Thus, overall, we printed alppla,ab.
Chapter 3.5.2
The question is asking about the following code snippet:
n = 4 x = 0 while n > 0: for i in range(n): x += 1 print(x) n -= 2
The question is not asking about what we'll be printing, so we can ignore the print statement (it's just helpful if you want to run the code snippet and track how exactly x is changing).
  1. We create a variable called n that has a value of 4
  2. We create a variable called x that has a value of 0
  3. Check the while-loop condition: n has a value of 4, so 4 > 0 is True, so we enter the body of the while-loop
  4. Python's range function is exclusive at the end, so range(n) iterates from 0, 1, ..., n-1. n has a value of 4, so range(n) is range(4), so i will be 0, then 1, then 2, then 3
    • When i is 0, we run x += 1, so x is incremented from 0 to 1
    • When i is 1, we run x += 1, so x is incremented from 1 to 2
    • When i is 2, we run x += 1, so x is incremented from 2 to 3
    • When i is 3, we run x += 1, so x is incremented from 3 to 4
  5. We have finished the for-loop, so we run n -= 2, so n is decremented from 4 to 2
  6. Check the while-loop condition: n has a value of 2, so 2 > 0 is True, so we enter the body of the while-loop
  7. n has a value of 2, so range(n) is range(2), so i will be 0, then 1
    • When i is 0, we run x += 1, so x is incremented from 4 to 5
    • When i is 1, we run x += 1, so x is incremented from 5 to 6
  8. We have finished the for-loop, so we run n -= 2, so n is decremented from 2 to 0
  9. Check the while-loop condition: n has a value of 0, so 0 > 0 is False, so we don't enter the body of the while-loop
Chapter 4.3.3
The question is asking about the following code snippet:
your_set = set() for i in range(10): if i % 2 == 0: your_set.add("even") else: your_set.add("odd")
First, it is important to remember that a Python set does not contain duplicates, and if we try to add something that already exists in the set, nothing happens.
  1. We create a variable called your_set that refers to a new empty set
  2. Python's range function is exclusive at the end, so range(10) iterates from 0, 1, ..., 9
    • When i is 0, i % 2 == 0 becomes 0 % 2 == 0, which is 0 == 0, which is True, so we enter the if-statement and add "even" to your_set
    • When i is 1, i % 2 == 0 becomes 1 % 2 == 0, which is 1 == 0, which is False, so we enter the else-statement and add "odd" to your_set
    • When i is 2, i % 2 == 0 becomes 2 % 2 == 0, which is 0 == 0, which is True, so we enter the if-statement and add "even" to your_set
    • When i is 3, i % 2 == 0 becomes 3 % 2 == 0, which is 1 == 0, which is False, so we enter the else-statement and add "odd" to your_set
    • Etc. Do the same for when i is 4, 5, 6, 7, 8, and 9
Overall, we added "even" and "odd" to your_set multiple times, but because Python sets simply ignore duplicate insertions, your_set only contains 2 elements: "even" and "odd".
Chapter 4.4.5
The question is asking about the following code snippet:
your_tuple = ("Hello", "Friends")
The question asks which of the following statements will cause a Python error:
  • Option (a): your_tuple = your_tuple + 1
    • This is invalid because of the your_tuple + 1 part: we cannot add a tuple with an int
  • Option (b): your_tuple[0] += 1
    • This is invalid for two reasons: we cannot add an int (1) to a string (your_tuple[0], which is "Hello"), and even if we could, tuples are immutable: we cannot modify/update the elements of your_tuple
  • Option (c): your_tuple = ("hello")
    • This is perfectly valid because we're not modifying the tuple itself: we're completely reassigning the your_tuple variable
    • Note that, while this statement will not cause a Python error, the variable your_tuple will be assigned to the string "hello" rather than to a new tuple, as the parentheses will be treated as operators rather than the beginning/end of a tuple
    • If we wanted your_tuple to be a tuple that only contains the single element "hello", we would need to do the following (notice the comma): your_tuple = ("hello",)
    • This is certainly confusing, but there's not really more explanation to this beyond just "the syntax Python uses to create a tuple with a single element is weird"
  • Option (d): your_tuple.append("!")
    • The append function exists for lists, but not for tuples because tuples are immutable
Chapter 4.5.3
The question is asking about the following code snippet:
keys = ["red", "blue", "green", "yellow", "green", "purple", "blue"] your_dict = dict() for key in keys: your_dict[key] = None
Essentially, this code snippet is iterating through each element of keys and, for each one, is storing the current key as a key in your_dict that is associated with the value None (remember that None is a Python keyword that essentially means "nothing").

However, remember that Python dictionaries do not support duplicate keys: if you try to assign a value to a key that already exists in the dictionary, you will simply overwrite that key's previous value.

Therefore, after running this code snippet, we will only store each of the unique keys exactly once, all with the same value (None). Because there are 5 unique elements in keys, my_dict will only have 5 (key,value) pairs: ("red",None), ("blue",None), ("green",None), ("yellow",None), and ("purple",None)
Chapter 6.2.3
  • Option (a) is true because, without a base case, you will recurse infinitely. For example, the following code snippet doesn't have a base case, so calling foo(0) will result in calling foo(1), which will result in calling foo(2), etc. in a never-ending series of recursive calls
    def foo(n): return foo(n+1)
  • Option (b) is false because we can define recursive functions on any type. Here's an example recursive function that recursively computes the length of a string:
    def rec_len(s): if s == "": # base case return 0 else: # recursive case return 1 + rec_len(s[1:])
  • Option (c) is false because an input corresponding to a base case does not need to be able to be broken into smaller inputs: it can be solved directly. For example, in the code example we provided for Option (b) to recursively compute the length of a string, the input "" (i.e., empty string) is a valid input to the recursive function, but it cannot be broken into smaller inputs
  • Option (d) is false. This is counter-intuitive, but consider the following example function (the input function[docs.python.org] prompts the user for some input):
    def get_age(): age = int(input("Enter your age: ")) if age > 0: # base case return age else: # recursive case return get_age()
    • This function keeps asking the user to enter their age until the user enters a positive age. It's a recursive function because it clearly calls itself, and it does indeed call itself with the "same input" (which is no input, as the function does not have any parameters)
Chapter 7.3.4
  • Option (a) is false because water is not an instance variable of the Lunch class: the instance variable as shown in 7.3.3 is drink. Thus, you can access the Drink object you had for lunch via your_lunch.drink, not your_lunch.water
  • Option (b) is false because, as shown in 7.3.3, patty is an instance variable of the Burger class, not of the Lunch class. As shown in 7.3.3, the Lunch class has an instance variable burger that refers to a Burger object, so you can access what type of patty you had via your_lunch.burger.patty, not your_lunch.patty
  • Option (c) is true: as shown in 7.3.3, the Lunch class has an instance variable called fries that refers to a Fries object, and the Fries class has an instance variable called flavor, so your_lunch.fries.flavor is valid
  • Option (d) is true because of the explanation for Option (a)
Chapter 7.3.10
The question is asking about the following code snippet:
my_drink = Drink("water", 500) my_burger = Burger("brioche", "pepperjack", "veggie", "ketchup", False, False, 2) my_fries = Fries("sweet potato", False) my_lunch = Lunch(my_drink, my_burger, my_fries) your_lunch = my_lunch your_lunch.drinkflavor = "soda" print(your_lunch == my_lunch, your_lunch is my_lunch)
The important part of the code is your_lunch = my_lunch, which creates a variable called your_lunch and has it refer to the exact same Lunch object that the variable my_lunch refers to. Because your_lunch and my_lunch are referring to the exact same Lunch object, your_lunch is my_lunch is True, and therefore, your_lunch == my_lunch is also True).

You may be wondering about what happens when we execute your_lunch.drink.flavor = "soda". Because your_lunch is referring to the exact same Lunch object as my_lunch, your_lunch.drink is referring to the exact same Drink object as my_lunch.drink (it's whatever Drink object that is referred to by the drink instance variable of the single Lunch object we have). Thus, by reassigning your_lunch.drink.flavor, we are also reassigning my_lunch.drink.flavor.
Chapter 8.2.4
The question is asking about the following code snippet:
arr = [1, 2, 3] ind = 42 den = 0 print(arr[ind]/den)
  1. We create a variable called arr that refers to the following list: [1, 2, 3]. Here is a depiction of this list that is labeled with the indices:
    Index: | 0 | 1 | 2 | Value: | 1 | 2 | 3 |
  2. We create a variable called ind that has a value of 42
  3. We create a variable called den that has a value of 0
  4. We execute print(arr[ind]/den)
    • This will first try to evaluate arr[ind], and then it'll try to evaluate the division of that value with den, and then it'll try to print the result
    • ind has a value of 42, so we plug it in: arr[ind] becomes arr[42]. However, arr only has 3 elements, so only the indices 0, 1, and 2 are valid. Thus, trying to access index 42 (which is out of bounds) will result in an IndexError
Chapter 8.2.5
The question is asking about the following code snippet:
arr = [1, 2, 3] ind = 2 den = 0 print(arr[ind]/den)
  1. We create a variable called arr that refers to the following list: [1, 2, 3]. Here is a depiction of this list that is labeled with the indices:
    Index: | 0 | 1 | 2 | Value: | 1 | 2 | 3 |
  2. We create a variable called ind that has a value of 2
  3. We create a variable called den that has a value of 0
  4. We execute print(arr[ind]/den)
    • This will first try to evaluate arr[ind], and then it'll try to evaluate the division of that value with den, and then it'll try to print the result
    • ind has a value of 2, so we plug it in: arr[ind] becomes arr[2], which returns the element at index 2 of arr, which is 3
    • arr[ind] has a value of 3 and den has a value of 0, so we plug them in: arr[ind]/den becomes 3/0. We are attempting to divide by 0, which will result in a ZeroDivisionError
Chapter 8.3.4
The question is asking about when we would want to use a default message parameter in the __init__() method of an Exception class.
  • Option (a) is incorrect because each Exception class should only throw one type of exception. Otherwise, it would somewhat defeat the purpose of having Exception classes in the first place: an Exception would no longer be specific and thus not as informative about what exact problem occurred during code execution
  • Option (b) is correct: by specifying a default message parameter value, we can optionally choose to specify a custom message when we throw an Exception (e.g. telling the user some information about what specific inputs caused the Exception)
  • Option (c) is correct: by specifying a default message parameter value, we can specify a default message (e.g. if we don't have any more specific information about what exactly caused the Exception)
  • Option (d) is incorrect: the message parameter has nothing to do with catching Exceptions
1 Comments
Tairy Hesticles 24 Feb, 2022 @ 10:57am 
Thanks for this guide! I'm new to programming and was already getting tripped up on parts of Chapter 1. It all makes a lot more sense with these detailed breakdowns.