ProgrammingLead Python Developer

What is modularity in Python, how to structure large projects, and what practices are considered best for organizing code?

Pass interviews with Hintsage AI assistant

Answer.

Modularity is the key to the scalability and maintainability of applications in Python. A proper modular structure allows you to divide a project into logically separated parts, making it easier to test, reuse, and maintain code.

Background

From the earliest versions, Python has supported modules—separate files with a .py extension that can be imported into each other. With the evolution of the language, packages (directories with init.py) and rich conventions for structuring large projects emerged (recommendations from PEP 8 and PEP 420).

Problem

Large projects, if not structured, quickly turn into chaos—monolithic code is difficult for team collaboration, leading to conflicts, lack of reusability, and code duplication.

Solution

Industry standards suggest the following approach:

  1. Code is divided into separate modules (distinct tasks/domains).
  2. Logically related modules are combined into packages (directories with __init__.py).
  3. A root package (for example, myproject) is created with sub-packages such as models, services, utils, api, etc.
  4. External dependencies are placed in separate directories (external, libs), while dependencies are specified in a requirements.txt or pyproject.toml file.

Example structure:

myproject/
    __init__.py
    models/
        __init__.py
        user.py
        product.py
    services/
        __init__.py
        payment.py
        order.py
    utils/
        __init__.py
        helpers.py
    main.py

Import within packages is done either relatively (from .models import user) or absolutely (from myproject.models import user).

Key features:

  • Division into modules facilitates testing and reuse.
  • init.py turns a directory into a package, allowing control over the public API.
  • Using a single entry point (main.py, app.py) instead of disparate scripts.

Trick Questions.

Can different parts of the project have the same name (for example, user.py in two sub-packages) without import issues?

No! When names collide, Python builds a namespace from the module hierarchy. If imports are made incorrectly (from the root without specifying the package), conflicts and obscure bugs may arise. It is recommended to use absolute imports or relative ones within packages.

Is it mandatory to have an init.py file in the package directory?

For older versions of Python (before 3.3) — yes, otherwise the directory is not considered a package. Starting with Python 3.3 (PEP 420), implicit namespace packages are supported, but for compatibility and clarity, it is better to always add init.py.

Should all functions and classes of a large project be in one file?

No. This is a classic anti-pattern—huge modules are hard to maintain, break reusability and testing, and create a high entry barrier for new employees.

Common Mistakes and Anti-Patterns

  • Monolithic files without division into modules.
  • Violation of naming conventions.
  • Hardcoded import paths, incompatibility of different environments.
  • Absence of init.py.

Real-Life Example

Negative Case

The project grew—the logic is in one or two files, hundreds of lines. A new employee finds it difficult to understand, edits break everything at once, and tests cover only the "main" part.

Pros:

  • Quick start, minimal files.

Cons:

  • Labor-intensive support, low scalability, frequent bugs when changes are made.

Positive Case

The project is structured in layers (models, services, utilities), each package is responsible for its zone of responsibility, and there is a separation of public and private APIs through init.py.

Pros:

  • Easy to test and update.
  • Easy to onboard new people.

Cons:

  • Requires thoughtful architecture design at the planning stage.