0%

Organizing a Program Across Files · practice

Choose an Entry Point

The project now has three files. Two of them are that define things and do nothing, and one of them is different.

main.py is the entry point: the file you run to start the program. This project has one, and it has a job the other files do not. Larger projects may offer several entry points for different uses.

What an entry point is for

An entry point answers one question: what does running this program actually do?

Everything else in a project is a capability. models.py describes what a question is. scoring.py can turn a score into a letter. Neither decides anything. The entry point is where the decisions live: which quiz, which learner, what to print, in what order.

That makes it the most specific file in the project, and the least reusable, which is exactly right. It is also why it should be short. When main.py is twenty lines you can read them and know what the program does. When it is two hundred, the program’s shape is hidden in the same file as its details.

The shape

Try it

Three things, in this order:

  1. Imports, saying what the program is built from.

  2. A main() holding the wiring.

  3. The guard, calling main() only when this file is run.

Putting the work in main() rather than at the top level is worth doing even though the guard alone would stop it running on import. A function can be called from a test, called twice, or called with different later. Top-level code can only ever happen once, in one way.

Why put the wiring in main() rather than directly under if __name__ == "__main__":?

Which file is __main__

Only one file in a run is __main__: the one you started. Every other file, however it got imported, has its own module name.

That has a practical consequence worth knowing. If models.py had a guarded demo at the bottom, running main.py would not trigger it, because models is not __main__ in that run. Running models.py directly would. Each file can carry its own demo without any of them interfering.

Reading a project by its entry point

Once a project is arranged this way, the fastest way to understand it is to open the entry point and read the imports.

from models import Attempt, Question, Quiz
from report import report_lines
from scoring import grade_letter, percentage

Three lines, and you know the program has a domain, a reporting layer, and scoring rules, before reading a single function. That is the payoff for the whole chapter: the structure is documentation that cannot go out of date, because it is the thing itself.

The exercise

main.py becomes a proper entry point. It gains the scoring module, and it keeps only what belongs to running the program.

Task

Turn main.py into a proper entry point.

Import what it needs: Attempt, Question, and Quiz from models, and grade_letter and percentage from scoring.

Keep build_quiz() and report_lines(attempt) here for now; the next lesson gives the report a home of its own. Extend report_lines to return a second line reading "Grade: <letter>", using the two scoring rather than doing the arithmetic itself.

main() holds the wiring and the printing. Nothing else in the file may run on import, and the file ends with the guard.

Running it should print the score line and the grade line.