Data Science and Advanced Programming · Session 2

Session 2: the Wooclap questions

The reading questions from class, to redo at home.

Answer each question on paper first, without running anything. Then open the answer. If you got it wrong, run the code in your workspace and find the line where your prediction and Python part ways.

Reading tasks

Task 1 · names are labels, not formulas

On paper, fill in a table: after each line, what is every name, and what is its type? Then predict what the print shows. Question: price changed on line 5. Why did old_price and value not change with it?

price = 102.3
old_price = price
shares = 4
value = shares * price
price = 105.0
shares += 6
print(old_price, price, shares, value)

What does the print show?

  1. 105.0 105.0 10 1050.0
  2. 102.3 105.0 10 409.2
  3. 102.3 105.0 10 1050.0
  4. 105.0 105.0 10 409.2
Show the answer

102.3 105.0 10 409.2

Assignment binds a name to a value once. old_price got the value 102.3, not "whatever price is". value was computed on line 4 with the numbers of that moment; nothing is ever recomputed.

Task 2 · the money disappeared

Buying shares at the market price does not make you richer or poorer: shares × price + cash is the same before and after a purchase. This code runs without an error, but it breaks that rule. Find the line, say in one sentence what it does wrong, and fix it.

shares = 4
price = 102.3
cash = 1000.0
wealth_before = shares * price + cash

shares = shares + 6
cash = cash - shares * price

wealth_after = shares * price + cash
print(wealth_before, wealth_after)

Which line breaks the rule?

  1. cash = cash - shares * price
  2. wealth_before = shares * price + cash
  3. wealth_after = shares * price + cash
  4. shares = shares + 6
Show the answer

cash = cash - shares * price

The buggy version prints 1409.2 1000.0. Cash is charged AFTER shares was raised to 10, so all 10 shares are paid for, not the 6 bought. The order of lines is state. Charge for what you buy, and check the rule with a tolerance, not ==.

Task 3 · the clever swap

Someone shows you a way to swap two numbers without a third name. Predict both printed lines, then run. Why does the trick work on the second pair (cents, whole numbers) and not on the first (francs, floats)?

a = 190.5
b = 102.3
a = a + b
b = a - b
a = a - b
print("Task 3 CHF:  ", a, b, a == 102.3)

a = 19050
b = 10230
a = a + b
b = a - b
a = a - b
print("Task 3 cents:", a, b, a == 10230)

Why does the trick fail on the francs?

  1. The names a and b are swapped twice
  2. Float addition rounds, so a + b - b is not exactly a
  3. 190.5 is too large for a float
  4. Python cannot subtract floats
Show the answer

Float addition rounds, so a + b - b is not exactly a

Every float operation rounds to the nearest number the machine can store, so (a + b) - b need not give back exactly a. Integers are exact. This is session 1's 0.1 + 0.2, hiding inside a "clever" trick.

Task 4 · the default that eats a value

A cash amount comes from a file. If the file has nothing (None), the program should assume 1000.0. Someone wrote it in one short line with or. Predict the three printed values. Which one is a lie, and why? (You can fix it tomorrow, with if.)

cash_from_file = 250.0
print(cash_from_file or 1000.0)

cash_from_file = 0.0
print(cash_from_file or 1000.0)

cash_from_file = None
print(cash_from_file or 1000.0)

Which result is wrong?

  1. 4a: 250.0 stayed 250.0
  2. 4c: None became 1000.0
  3. 4b: 0.0 became 1000.0
  4. None of them
Show the answer

4b: 0.0 became 1000.0

x or y gives x if x counts as true, otherwise y. None counts as false, as intended, but so does 0.0: a client with exactly zero cash suddenly has 1000.0. Task 4b is the lie. The fix needs to test for None specifically, which is an if (session 3).

Task 5 · one fee, two roundings

A 0.25 % fee on a 1070.00 CHF trade is exactly 2.675 CHF on paper. Predict both printed numbers. They are "the same" 2.675. Why do they round differently?

a = round(2.675, 2)
b = round(1070.00 * 0.0025, 2)
print(a, b)

What does the line print?

  1. 2.67 2.68
  2. 2.68 2.67
  3. 2.67 2.67
  4. 2.68 2.68
Show the answer

2.67 2.68

2.675 is stored slightly below 2.675, so it rounds down. The product 1070.00 × 0.0025 is stored slightly above (2.6750000000000003), so it rounds up. Same number on paper, two different numbers in memory. Money in floats means the rounding of a fee can depend on how you computed it.

Self-check (home questionnaire)

Check 1

What does this print?

print(type(7 / 7))
  1. <class 'str'>
  2. <class 'bool'>
  3. <class 'int'>
  4. <class 'float'>
Show the answer

<class 'float'>

Check 2

What does this print?

print(7 // 2, 7 % 2, -7 // 2)
  1. 3.5 1 -3.5
  2. 3 0 -4
  3. 3 1 -4
  4. 3 1 -3
Show the answer

3 1 -4

Check 3

What does this print?

print("3" * 2 + "1")
  1. TypeError
  2. 61
  3. 331
  4. 7
Show the answer

331

Check 4

What does this print?

print(2 + 3 * 4 ** 2)
  1. 50
  2. 62
  3. 400
  4. 146
Show the answer

50

Check 5

What does this print?

x = 5; x += x * 2; print(x)
  1. 20
  2. 15
  3. 10
  4. 25
Show the answer

15

Check 6

What does this print?

print(int("4") + int(float("2.9")))
  1. 6.9
  2. 6
  3. ValueError
  4. 7
Show the answer

6

Check 7

What does this print?

print(0.1 + 0.2 == 0.3, abs(0.1 + 0.2 - 0.3) < 0.01)
  1. False False
  2. True False
  3. True True
  4. False True
Show the answer

False True

Check 8

What does this print?

print(bool(""), bool("0"), bool(0.0))
  1. False True False
  2. False False False
  3. False True True
  4. True True False
Show the answer

False True False

Check 9

Which error does this give?

print(int("4.5"))
  1. NameError
  2. ValueError
  3. SyntaxError
  4. TypeError
Show the answer

ValueError

Check 10

Which error does this give?

print("4" + 6)
  1. NameError
  2. TypeError
  3. ValueError
  4. 46
Show the answer

TypeError

Check 11

The rule for money from the lecture: when do you round?

  1. Before comparing with ==
  2. Only for display, at the very end
  3. Never; floats are exact
  4. After every calculation
Show the answer

Only for display, at the very end