Organizing a Python Project

Structure code you'll come back to

Beginner 11 min

In this lesson

Organising a Python project means splitting your code into modules and folders with a sensible layout, so it’s easier to navigate, reuse, and return to months later. Once a program grows past a single file, this structure matters — this capstone ties together modules, environments, and good habits.

Explain it like I’m 5

Organising a project is like tidying a workshop: tools grouped sensibly, a label on the door, and a list of what you need. You can find things instantly and so can anyone who visits.

Split code into modules by responsibility

Don’t cram everything into one giant file. Group related functions into modules (.py files) named for what they do: data.py for loading data, report.py for output. Import between them as you learned earlier. Each file having one clear job makes the whole project easier to read and change.

Example
# data.py — knows how to get the data
def load_scores():
    return [88, 72, 95]

# main.py — uses data.py, stays focused on the flow
import data

scores = data.load_scores()
print("Average:", sum(scores) / len(scores))
Output
Average: 85.0
Two small files, each with one job.

A sensible folder layout

A typical small project has a top-level folder with your code, a README.md explaining what it is and how to run it, a requirements.txt listing dependencies, a .gitignore (including .venv/), and perhaps a tests/ folder. You don’t need all of this on day one, but knowing the shape helps you grow into it.

Example
wordcounter/
    wordcount.py       # the program
    data.py            # helper module
    requirements.txt   # pinned dependencies
    README.md          # what it is and how to run it
    .gitignore         # lists .venv/ so it isn't committed
    .venv/             # the virtual environment (ignored)
A clear home for each kind of file.

The if __name__ == '__main__' guard

Code at the top level of a file runs whenever the file is imported, which is usually not what you want. Wrapping your ‘run the program’ code in if __name__ == "__main__": means it only runs when the file is executed directly, not when imported. This lets a file be both a reusable module and a runnable script.

Example
# greet.py — can be imported OR run directly
def greet(name):
    return f"Hello, {name}!"

def main():
    print(greet("world"))

if __name__ == "__main__":
    main()
Output
Hello, world!
The __main__ guard: runnable as a script, safe to import.

Add a __main__ guard so main() runs when the file is executed directly. Running it should print the greeting.

def greet(name):
    return f"Hello, {name}!"

def main():
    print(greet("Python"))

# add the guard so main() runs here

Habits that keep it maintainable

Use a virtual environment per project; keep a requirements.txt current; write a short README so future-you knows how to start it; give files, functions, and variables clear names. None of these are hard individually — together they’re the difference between a project you can pick back up and one you dread reopening.

Tools that keep quality high

As projects grow, a handful of tools keep them healthy — all optional, but worth knowing they exist. Formatters like black and linters like ruff automatically tidy your style and flag likely mistakes, so you stop debating spacing. A tests/ folder with automated tests lets you change code without fear of breaking it. And type hints document the types you expect and let tools catch mismatches early.

None of these are required to write Python — but each makes a project you return to far easier to trust. That’s a fitting place to finish the beginner path: from here, the best next step is to build things. Try the projects, which put these fundamentals to work.

Example
# Type hints document the expected types; Python doesn't enforce them,
# but editors and linters use them to catch mistakes early.
def greet(name: str, times: int = 1) -> str:
    return (f"Hi {name}! " * times).strip()

print(greet("Ada"))
print(greet("Bo", 3))
Output
Hi Ada!
Hi Bo! Hi Bo! Hi Bo!
Type hints: documentation that tools can check.

Common mistake: Top-level code that runs on import

Why it happens:

Code written at the module’s top level executes every time the file is imported, causing surprising output or side effects.

How to fix it:

Move ‘run the program’ code into a main() function and call it from inside an if __name__ == "__main__": guard.

Common mistake: Letting one file grow without limit

Why it happens:

It’s easy to keep adding to a single script until it’s hundreds of lines and hard to navigate.

How to fix it:

Split related functions into separate modules by responsibility, and import between them. Each file should have a clear, single purpose.

What does if __name__ == "__main__": do?

Why split a program into multiple modules?

Mini exercise (medium)

Sketch a folder layout for a small ‘word counter’ project: where would the code, the dependency list, the readme, and the ignored virtual environment go? Then describe what the __main__ guard in the main file is for.

The folder layout is something you sketch on paper — but the __main__ guard is real code. Add it so main() runs only when this file is the program being run.

def main():
    return "word counter ran"

result = None
# TODO: set result = main(), but only when this file is run directly

What to learn next

You learned to split code into modules, lay out a project folder sensibly, use the __main__ guard so a file can be both run directly and imported, and keep README and requirements files alongside your code. You added that guard yourself so main() runs only when the file is executed directly.

That’s the entire beginner foundation, from your first print() to a well-structured project — congratulations on finishing the Beginner path. From here, the Intermediate path takes you from writing scripts to designing programs, starting with Classes and Objects Explained Simply. It’s also a great moment to build something end to end — try a guided project like the Number Guessing Game or the To-Do List CLI. When you’re ready, continue to Intermediate or pick a project.