Use existing libraries
Python's built-in functions are only a small part of the available ecosystem. A module is a Python file or compiled component containing related definitions. A package groups modules for installation and reuse. Python ships with a large standard library, while the Python Package Index contains packages maintained outside Python itself.
Modern analytical programs mostly connect existing components. If a well-maintained library already performs an operation, using and understanding its documented implementation is generally preferable to writing a substitute from scratch. Your code still has important work to do: it defines the local data contract, connects returned values and determines what the rest of the program does with them.
For every unfamiliar library call, answer four questions from its documentation and a tiny experiment:
- What object or data shape does it accept?
- What type and shape does it return?
- Which parameters materially change the result?
- Which project requirement still belongs in our own code?
Inspect unfamiliar values while the program runs
Documentation tells you what a library is intended to return; inspecting a small real result shows what your program actually received. You can use print, type and dir for quick checks:
result = unfamiliar_function(example_data)
print(type(result))
print(result)
print(dir(result))type(result) identifies the kind of object. dir(result) lists the names available on it, although the documentation is usually clearer about which of those names form the public interface.
For a closer look, Python's breakpoint() function pauses the program at that line and opens an interactive debugging prompt:
result = unfamiliar_function(example_data)
breakpoint()
rows = transform(result)At the prompt you can inspect result, try an indexing operation or call type(result) before allowing execution to continue. Enter continue (or c) to resume. Remove temporary breakpoint() calls when you have finished investigating. VS Code's built-in debugger provides the same kind of inspection through its graphical interface.
Importing from the standard library
The import statement makes a module available under its module name:
import collections
counts = collections.Counter(["Finnish", "Swedish", "Finnish"])
print(counts)Counter({'Finnish': 2, 'Swedish': 1})
The prefix collections. makes the origin of Counter visible. This is especially useful when reading a larger program with several dependencies.
Modules may also be imported under an explicit shorter name:
import collections as col
counts = col.Counter(["Finnish", "Swedish", "Finnish"])The name after as is the name used in the rest of the file. Later libraries have widely recognised aliases, but an abbreviation should still be understandable to readers.
You can instead import one or more documented names directly:
from collections import Counter
counts = Counter(["Finnish", "Swedish", "Finnish"])In this form the module prefix is not used. Avoid from module import *: it imports many names without showing where they came from and makes generated code harder to inspect.
Finding what a module provides
The Python standard-library documentation describes the modules supplied with Python, their functions and classes, their parameters, and the objects they return. Documentation for external packages is maintained by those projects.
You can also inspect the names defined in an imported module:
import collections
print(dir(collections))The result includes public tools such as Counter and defaultdict, as well as names beginning with underscores which are implementation details. Use dir to orient yourself, then use the documentation to learn the intended interface. An agent can help locate and explain the relevant documentation, but verify its claims against the documented signature and a small result.
The same counting tool answers the question left open in the Hume investigation earlier in this part.
Inspect constants as well as functions
Modules contain more than functions. They may also define classes and named constant values. The string module, for example, provides groups of characters such as ascii_letters and punctuation.
ascii_letters contains only the unaccented uppercase and lowercase letters used in ASCII. Characters such as é and ü are letters in ordinary language but are not members of that particular constant. A library name must therefore be interpreted according to its documented definition, not according to what sounds plausible from its name.
Let a library parse a standard format
The standard library's csv module already handles delimiters, quoted values and line endings. A simple line.split(",") cannot correctly parse a quoted field which itself contains a comma, so we should not write another CSV parser by splitting lines ourselves.
Not every file uses a comma. The city-bike data you parsed earlier is separated by semicolons, precisely because some station names contain a comma of their own:
24.820098999669142;60.18498699955046;260;Aalto-yliopisto (M), Tietotie;20;Yes;539csv.reader reads a file into one list of fields per row, and takes the separator as the keyword argument delimiter:
import csv
with open("stations.csv") as my_file:
for row in csv.reader(my_file, delimiter=";"):
print(row)The module also handles the case which defeats split even when the delimiter is a comma. A row written as
"aaa,bbb","ccc,ddd"is correctly returned as the two fields ['aaa,bbb', 'ccc,ddd'], because a quoted field may contain the delimiter. Splitting that line yourself would produce four broken values.
Fields read this way are accessed by position. csv.DictReader instead uses the first row as field names and produces a dictionary for each later row. This makes the resulting records easier to inspect and less dependent on remembering column positions. Unless you explicitly convert them, CSV field values are strings—even a field which looks like a year.
Installed and bundled packages
External packages must normally be installed into the active project environment before they can be imported. In the isolated environment created for a local project, a package can commonly be installed with a command of this form:
python -m pip install package-nameThe command must use the same Python environment which runs the program. Installing a package changes the environment; importing it makes its definitions available to one program. In a reproducible project, dependency names and versions are also recorded in a dependency file rather than relying on an undocumented global installation.
In an ordinary local project, a coding agent can propose a suitable established package, add it to the project's dependency file and install it. You should still inspect what job the dependency performs, whether it is actively maintained, and what data its public interface accepts and returns.
The remotely assessed TMC exercises are much more constrained than an ordinary project. They run in a fixed environment, cannot be assumed to install arbitrary packages, and must not depend on downloading data or models while the checks run. This is a limitation of the exercise runner, not a recommendation to reimplement mature libraries in real projects.
The course therefore uses this boundary:
- Parts 5–6 use Python's standard library or code visibly bundled with an exercise.
- A Part 7 exercise may use pandas, seaborn, scikit-learn or spaCy only when the exercise names that dependency and maintainers have confirmed the required version and model in the current runner. Do not add another package to a TMC solution merely because an agent suggests it. You will install these four libraries on your own computer at the start of Part 7.
- Part 8 runs locally in a separately pinned environment and can use a real dashboard framework. Add only dependencies which have a clear role, and record them in that environment.
When TMC does not provide a useful library, the honest options are to use the limited tools named by the exercise or to move the task outside TMC. Course-written imitations of major analytical libraries would teach the wrong interface and are not a general solution to the runner limitation.
Occasionally an exercise needs a small package which is not installed remotely. In that case the package may be bundled visibly with the exercise. It is still existing library code: inspect its public documentation and interface, but do not edit its internal implementation unless the task explicitly asks you to.
The package is bundled here only because it is absent from the runner and small enough to ship with the exercise. Do not imitate this arrangement for pandas, spaCy, scikit-learn or seaborn. Use them only in the Part 7 exercises where runner support has been confirmed.
You can check your current points from the blue blob in the bottom-right corner of the page.