Skip to main content

How to Create and Structure a Python Package

Intermediate20 min4 exercises60 XP
0/4 exercises

Imagine you have a filing cabinet. Right now, all your papers are thrown in one big drawer — recipes mixed with homework mixed with tax forms. Finding anything is a nightmare.

A Python package is like adding labeled folders to that filing cabinet. Instead of one giant file with all your code, you split it into organized folders where each folder handles one topic.

In this tutorial, you'll learn how Python packages work, what the mysterious __init__.py file does, and how to structure your own projects like a professional developer.

What Is a Python Package?

You already know that a module is a single .py file. A package takes it one step further — it's a folder that contains multiple modules.

The key ingredient that turns a regular folder into a Python package is a special file called __init__.py. When Python sees a folder with this file, it knows: "This folder is a package I can import from."

Simulating a package with two modules
Loading editor...

In a real project, each function above would live in its own file inside the mypackage/ folder. You'd import them like from mypackage.greetings import say_hello.


What Does __init__.py Do?

Think of __init__.py as the front desk of a building. When someone walks in, the front desk tells them what's available and where to go.

The __init__.py file runs automatically whenever you import the package. It can be completely empty, or it can contain code that sets up the package — like importing key functions so users don't have to dig through submodules.

How __init__.py works as a front desk
Loading editor...

An empty __init__.py is perfectly fine. It just tells Python "this folder is a package." But adding imports to it creates a cleaner experience for anyone using your package.

Controlling exports with __all__
Loading editor...

How Should You Structure a Python Package?

A well-organized package is like a well-organized kitchen. Pots go in one cabinet, spices in another. Anyone walking in can find what they need without opening every drawer.

Here's a typical layout for a Python project with a package inside it:

A professional project layout
Loading editor...

Notice the src/ folder. This is called the src layout and is recommended by the Python Packaging Authority. It prevents accidental imports from your project root instead of the installed package.

Visualizing nested packages
Loading editor...

Each sub-folder that has an __init__.py is its own sub-package. You can nest as deep as you need, but try to keep it to 2-3 levels. Deeper nesting usually means your project needs a redesign.


What Are Relative vs Absolute Imports?

When modules inside a package need to import from each other, you have two choices: absolute imports and relative imports.

An absolute import spells out the full path from the top-level package. A relative import uses dots to say "import from nearby." It's like the difference between giving a full street address vs saying "the house next door."

Absolute Import
# Inside mypackage/models/user.py
from mypackage.utils import validate_email
from mypackage.core import Database
Relative Import
# Inside mypackage/models/user.py
from ..utils import validate_email
from ..core import Database

In relative imports, a single dot . means "current package" and double dots .. mean "parent package." Three dots ... mean "grandparent," and so on.

Understanding dot notation in relative imports
Loading editor...

How Do You Build a Complete Package from Scratch?

Let's walk through building a small but complete package. We'll simulate the file structure in a single script since we're in a browser, but the logic is exactly what you'd put in separate files.

A complete mathkit package simulation
Loading editor...

In a real project, each section above would be its own file. The __init__.py would import add, subtract, and format_result so users can access them directly from mathkit.


Practice Exercises

Time to practice! These exercises test your understanding of package structure, __init__.py, and imports.

Build a Package Structure Dictionary
Write Code

Create a function called get_package_structure() that returns a dictionary representing a Python package structure. The dictionary should have a key 'webapp' whose value is another dictionary containing these keys (in any order): '__init__.py', 'routes.py', 'models.py', and 'utils.py'. Each value should be the string 'module'.

Loading editor...
Fix the Broken __all__ Export
Fix the Bug

The code below defines a simulated package with a __all__ list and three functions. The get_public_api() function should return only the names listed in __all__, but there are bugs. Fix them so the output shows exactly the two public functions.

Loading editor...
Predict the Import Path
Predict Output

Read the code below carefully. It simulates how Python resolves import paths in a nested package. What will it print?

Loading editor...
Refactor Into a Package Registry
Refactor

The code below uses separate variables to track modules in a package. Refactor it into a single class called PackageRegistry with:

  • An __init__ method that sets the package name and an empty dictionary modules
  • A register(module_name, description) method that adds to modules
  • A get_info() method that returns a formatted string showing the package name and each module on its own line in the format - module_name: description
  • The output must match exactly.

    Loading editor...