Repository navigation
run_exercise.py: why run_name='__main__', and should RUNNABLE auto-register?
#15
|
The runner in runpy.run_path(str(path), run_name="__main__")and hardcodes: RUNNABLE = {
"4": "exercise4/answer.py",
"5": "exercise5/answer.py",
"6": "exercise6/answer.py",
"7": "exercise7/answer.py",
"guess": "guess-game.py",
"todo": "to-do manager.py",
}Two questions: (1) Is |
Replies: 1 comment
|
Why Should RUNNABLE auto-register? Yes, trivially, and it removes the "added exercise 8, forgot the runner" failure mode: RUNNABLE = {
p.parent.name.removeprefix("exercise"): str(p.relative_to(ANSWERS))
for p in sorted(ANSWERS.glob("exercise*/answer.py"))
}
RUNNABLE.update({
"guess": "guess-game.py",
"todo": "to-do manager.py",
})The trade-off: the explicit dict is a curated list (stable keys, only things you're confident run cleanly); globbing is everything that matches (half-finished answers become runnable with ugly tracebacks). Given this repo's answers are one-file scripts that always print, globbing is safe here — the |
Why
run_name="__main__":runpy.run_pathexecutes the file in a fresh namespace, and by default sets that namespace's__name__to the path string ("answer.py"or similar) — not"__main__". That means anyif __name__ == "__main__":guard in the target file would never fire, and scripts that rely on the guard (plus anything that checks__main__semantics) would print nothing. Passingrun_name="__main__"makes the file behave exactly as if you'd typedpython answers/exercise4/answer.py— which is the whole point of a runner. (One side effect to know: if the target file doesn't guard its top-level prints, they run either way —run_nameonly matters for guarded code and__main__checks.)Should…