mass = 46
name = "ethanol"
print(type(mass), type(name), type(mass / 2))<class 'int'> <class 'str'> <class 'float'>
5 min of teaching15 min of exercisesbeginner
0.1 + 0.2 == 0.3 is False and why 7 / 2 and 7 // 2 differ.Chapter 1 assumes you can already write a loop and a function in Python and are not frightened by an error message. It does not assume NumPy, pandas or anything scientific. The ten questions below test exactly that boundary. For each one, read the snippet, decide what it prints (or what is wrong with it), write your answer down, and only then open the solution. Keep score; the last section tells you what to do with it.
This whole page is one long predict before you run exercise. The solutions contain the real output, so the honesty rule matters more than usual: commit to an answer, in writing, before you click Show solution. If you want to run the snippets yourself, use the notebook you created in the setup episode.
Two conventions will fight your intuition. First, Python counts from 0: the first element of a list is xs[0], and the \(n\)-th is xs[n-1]. Second, ranges and slices are half-open intervals \([a, b)\): range(2, 5) is \(\{2, 3, 4\}\) and xs[2:5] takes positions 2, 3 and 4. The pay-off is that len(xs[a:b]) is simply \(b - a\), and xs[:k] + xs[k:] is always xs again, with no \(\pm 1\) bookkeeping. Once you see 0-based indices as offsets from the start rather than ordinal positions, both conventions feel natural.
1. Types and variables
What does this print?
<class 'int'> <class 'str'> <class 'float'>
46 is an int, text in quotes is a str, and dividing with / always produces a float, even when the result is a whole number (46 / 2 is 23.0, not 23). Python chooses the type from the value; you never declare it. The type matters because it decides what operations mean: "46" + "2" is "462", while 46 + 2 is 48.
2. Lists and dicts
What does this print, and which line would fail if you swapped masses for elements in the last print?
C 12.011
3 3
A list is ordered and indexed by position, so elements[1] is the second item, "C". A dict maps keys to values, so masses["C"] looks up the key "C". Swapping them, elements["C"] raises TypeError: list indices must be integers or slices, not str, and masses[1] raises KeyError: 1, because no key equals the integer 1. Use a list when order matters, a dict when you look things up by name.
3. Slicing
What do the four expressions evaluate to?
s[1:4] starts at index 1 (t) and stops before index 4, giving three characters. Negative indices count from the end, so s[-1] is the last character. An omitted start means “from the beginning” and an omitted end means “to the end”; s[:3] and s[3:] together rebuild the string with nothing lost or duplicated. Exactly the same rules apply to lists, and in Chapter 1 to NumPy arrays and pandas rows.
4. for and range
What does this print?
2 5 8 | total: 15
range(start, stop, step) produces 2, 5, 8 and stops before reaching 10. end=" " replaces the newline that print normally adds with a space, which is why the three numbers share a line. The final print is outside the loop (not indented), so it runs once. Indentation is not decoration in Python; it is the block structure.
5. Functions and return
What does this print? There is a bug; find it.
The function computes x * 2 and throws the value away: without a return statement every function returns None. The fix is return x * 2. This bug produces no error at the call site; the None travels on until something tries to use it, typically with a confusing TypeError: unsupported operand type(s) for *: 'NoneType' and 'int' several lines later. When a value is unexpectedly None, look for a missing return first.
6. f-strings
What does this print?
An f-stringf-stringA string literal prefixed with f that embeds expressions in braces, with optional formatting such as {x:.2f}. evaluates whatever is inside the braces and inserts it into the text. After a colon comes a format specifier: .2f means “fixed-point with two decimals”. {mass = } is a debugging shortcut that prints the expression and its value. You will use :.3f constantly to report model metrics; printing a raw float with sixteen digits tells the reader nothing and hides the number.
7. A comprehension
What does this evaluate to? Then write the equivalent for loop.
A list comprehensionlist comprehensionA one-line way to build a list from another sequence: [f(x) for x in items if cond]. reads left to right as “the value n * n, for each n in range(6), keeping those where n is even”. The equivalent loop is:
Both are fine. The comprehension is preferred when the transformation fits on one line; the loop is clearer when it does not. If you ever need to run something for its side effect (printing, saving), write the loop.
8. Read the traceback
This code was run and produced the traceback below. Which line is the problem, and what is the fix?
Traceback (most recent call last):
File "molar.py", line 9, in <module>
print(molar_mass("He"))
File "molar.py", line 6, in molar_mass
total += masses[element]
KeyError: 'e'
Read it from the bottom. The last line is the error: KeyError: 'e', meaning the dict was asked for a key 'e' it does not have. The line just above says where: line 6, total += masses[element], inside molar_mass. The line above that is the call that got us there, line 9. So the tracebacktracebackPython’s error report: read it from the bottom (the error) up (where it happened). is a trail from your top-level call down to the failing line, innermost last.
Why 'e'? Iterating over a string gives one character at a time: for element in "He" yields "H" and then "e". The function therefore works for "CO" by accident and fails for any two-letter element. The fix has two parts: pass a list of element symbols rather than a string, so that "He" stays one token, and add helium to the dict:
(44.009, 4.0026)
The habit to take away: last line first, then the nearest line of your code, then ask what value made that line fail.
9. Importing a module
What is wrong here, and what does the corrected version print?
import math makes the module available under the name math; its contents are reached with a dot. sqrt on its own is undefined, so the second line raises NameError: name 'sqrt' is not defined. Either qualify it or import the name explicitly:
Both print 4.0 (a float, because sqrt always returns one). In this course you will see import numpy as np and import pandas as pd: the as gives the module a short alias, after which everything is np.something. from numpy import * is never used, because it hides where names come from.
10. Floats and division
What does each line print? One of them surprises almost everyone.
False
0.30000000000000004
3.5 3 1 -4
Neither 0.1 nor 0.2 can be stored exactly in binary floating point, any more than 1/3 can be written exactly in decimal. The tiny rounding errors in each add up to a number that is not the same float as 0.3. The rule is: never compare floats with ==; compare with a tolerance instead:
For division: / is true division and always returns a float; // is floor division, rounding towards negative infinity, which is why -7 // 2 is -4 and not -3; % is the remainder. Mixing up / and // is a quiet way to turn an index into a float (xs[n / 2] fails with TypeError, xs[n // 2] works). NumPy arrays follow the same rules, and np.isclose plays the role of math.isclose for whole arrays.
Count the questions you got right before opening the solution.
All three refreshers are free and go well beyond what this page tests:
Whichever you pick, type every example rather than reading it. The questions on this page are the kind of thing you will meet again, with arrays and tables in place of lists, in the first two episodes of Chapter 1.
Each question here reappears in Chapter 1 wearing scientific clothes. Slicing becomes selecting rows of a table in episode 1.3; the loop over range becomes a NumPy operation on a whole array at once in episode 1.2; the traceback you read above is the first of many, and reading them well is a larger part of data work than anyone admits. The float comparison matters from Chapter 2 on, where you will compare model metrics that differ in the third decimal and need to know whether that difference is real.