Python Programming · Foundations

Python Packages

Want it in plain words first? Jump to Eli explains — the same idea, no jargon.
On this page 9 sections
  1. In 30 seconds
  2. Why this matters
  3. The college version
  4. Eli explains
  5. Worked example
  6. Key takeaway
  7. Quick check
  8. Study tools
  9. Sources & references

In 30 seconds

In Python, an organizes modules under a dotted name such as garden.tools. It helps a program keep related code from colliding or becoming one huge file. That import-time idea is different from a : the versioned bundle that an installer such as pip installs. The two often relate, but their names and boundaries need not match. A normal package usually has __init__.py; namespace packages are a deliberate exception.

Why this matters

Packages give a growing program an address system for its code. Reading from garden import tools tells a reader both what is wanted and where it belongs. The import-package versus distribution-package distinction also prevents a common debugging mistake: assuming the name typed to an installer must be the name used after import. Finally, knowing the limited role of a helps students separate organizing code from isolating a project's installed dependencies.

The college version

Packages organize names that Python can import

A module is one importable unit of Python code; a package is an importable module that can contain other modules or packages. Packages give those contained units dotted names. In garden.tools, garden is the package and tools is a module or subpackage inside it. Dotted names are more than a filing metaphor: they make the package hierarchy part of the import name. In an import written as import garden.tools, every component before the last one must be a package. The final component may be either a module or another package.

This organization matters when distinct parts of a program need similarly named things. A project can put plant-related behavior under garden and reporting behavior under reports instead of putting every definition into one file. The package name supplies context for a module name. It also lets a reader recognize that garden.tools and reports.tools are different addresses even though both end in tools. The import system searches for the requested name and binds the imported result; this lesson focuses on reading and designing those names, not on every detail of the search machinery.

A package is not simply any folder with Python files. It is an import-system concept. The files and directories on disk are a common way to provide it, but what matters here is whether Python recognizes the structure as an importable package. That is why the details of __init__.py and namespace packages deserve careful treatment.

Regular packages, init.py, and the namespace exception

A normally has an __init__.py file in its directory. Python executes that file when the regular package is imported. The file can be empty; its presence still communicates the regular-package form. It can also contain initialization code or define names the package deliberately exposes. Beginners sometimes treat __init__.py as a required place to put all application code. It is not. Keeping it small—or empty when appropriate—often makes the package boundary clearer.

The word “normally” is important. Python also supports native namespace packages. A has no __init__.py file, and its portions can be located in more than one directory. That feature is useful in some larger ecosystems, but it changes the simple folder rule. Therefore, the accurate beginner rule is: use __init__.py for an ordinary regular package; do not conclude that every importable package must contain one. A missing file can be an error in a project that intended a regular package, or it can be intentional namespace-package design.

For a small project, an explicit regular package is usually the clearest teaching example. A directory named garden can contain __init__.py and tools.py; then from garden import tools imports the tools submodule. This lesson does not prescribe a project layout for every application, nor does it cover relative-import technique. It establishes the naming and structure needed to recognize what an import package is.

Import packages are not distribution packages

Packaging conversations use “package” in a second sense. A distribution package is the versioned artifact that an installer handles. It carries metadata and can provide code, data, or other resources to an environment. An import package, by contrast, is the hierarchy Python makes available to an import statement. These concepts often line up well enough to feel identical, but they are not guaranteed to do so. One distribution can provide several import packages; several distributions can contribute portions to a namespace package; and the distribution name may differ from the name written in import.

That distinction guides a sensible troubleshooting question. If an installer reports success but import fails, do not merely repeat the same command. Check the documented import name and the Python environment being used. Conversely, a successful import name does not identify every distribution that supplied it. The lesson is not an installation manual, so it stops before commands, build configuration, and dependency resolution. The central point is to avoid treating the installer label as the language's namespace.

A virtual environment is related but separate again. It is an isolated Python environment, commonly created for one project. Pip is commonly used within that environment to install distributions. The environment controls which installed distributions are available to that interpreter; the import system then uses available code to resolve imports. Package organization answers “how is this code named?” A virtual environment answers “which project environment is this interpreter using?” Keeping those questions separate makes both concepts easier to reason about.

Eli, the EliExplains learning guide

Eli explains

The same idea, in plain words

Explain it like I’m 10

Imagine a library with labeled rooms. garden is one room, and garden.tools is a shelf inside that room. The dotted label helps you find the right code without mixing it with a different shelf named tools elsewhere. A normal room has a small sign called __init__.py that tells Python it is a regular room. Some advanced libraries deliberately combine several locations into one shared room; those are namespace packages and do not use that sign.

The box delivered to the library is a different thing. That box is like a distribution package: it is what an installer handles. A box might stock one room, several rooms, or part of a shared room. So the label on the delivery box need not be the exact label you use to find a shelf in Python.

Picture it like this

An import package is a labeled room-and-shelf address inside a library; a distribution package is a delivery box that may stock that address.

Where the picture stops working

Real imports use Python's import system rather than physical rooms, and a distribution can include non-code resources. The analogy is only for separating an address used by code from an artifact handled by installation tools.

Worked example

Create this small layout, then run app.py from the directory that contains app.py and the garden directory:

garden/
    __init__.py
    tools.py
app.py

Put this in garden/tools.py:

def common_name():
    return "fern"

Put this in app.py:

from garden import tools

print(tools.common_name())

The output is fern. garden is the regular package because its directory contains __init__.py; tools is its submodule. The expression tools.common_name() uses a name provided by that submodule. No installer command appears here: this example demonstrates the import-package layout only. A project could obtain code in many ways, but an import statement works with the import name that is available to the current interpreter.

Key takeaway

Use packages to give related modules clear dotted import names. Keep the import-time meaning separate from the distribution artifacts that tools install, and remember that __init__.py is normal for regular packages but not for namespace packages.

Quick check

3 questions here, of 5 in this lesson’s practice set. Answers stay hidden until you check.

Question 1 of 3foundational

What is an import package in Python?

Choose an answer, then check it.
Question 2 of 3intermediate

In import garden.tools, what must garden be?

Choose an answer, then check it.
Question 3 of 3intermediate

A project directory has no __init__.py, yet Python intentionally combines its contents with a same-named directory elsewhere. Which concept best describes this design?

Choose an answer, then check it.
Practice all 5

Keep learning

Ready to build on this? Continue to the next lesson.

Practice this lesson
Study tools & related lessonsYou’ll learn to · Common mistakes · Easily confused · Key vocabulary · Related

You’ll learn to

  • Define an import package and a dotted module name.
  • Distinguish a regular package from a namespace package.
  • Explain the ordinary role of __init__.py in a regular package.
  • Distinguish an import package from a distribution package.
  • Apply a package import to a small project layout.

Common mistakes

  • Calling every directory with Python files a package.

    Use the import-system distinction: a regular package normally has __init__.py; a namespace package is the documented exception.

  • Assuming a pip install name must equal the import name.

    Consult the distribution's documentation; a distribution package and import package do not have a required one-to-one naming relationship.

  • Putting all project code in __init__.py.

    Treat it as regular-package initialization or an intentionally exposed interface; place distinct behavior in appropriately named modules.

  • Treating a virtual environment as a code-organizing package.

    A package organizes import names, while a virtual environment isolates the interpreter and installed distributions for a project.

Easily confused

import package vs. distribution package

An import package is a code namespace used by import; a distribution package is a versioned artifact handled by installation tools.

regular package vs. namespace package

A regular package normally has __init__.py; a namespace package has no such file and can span multiple directories.

package vs. virtual environment

A package organizes importable code names; a virtual environment isolates an interpreter's installed distributions.

Key vocabulary

import package
An importable Python module that can contain submodules or recursively other packages.
dotted module name
An import name with periods that expresses containment, such as garden.tools.
regular package
A package form normally identified by an __init__.py file in its directory.
namespace package
A package whose portions can be found in multiple directories and that does not use an __init__.py file.
distribution package
A versioned artifact that an installer handles and that may provide importable code or other resources.
virtual environment
An isolated Python environment used to keep a project's installed packages separate from other environments.

Sources & references

  1. The Python Tutorial — 6. Modules (Packages) — Python Software Foundation
  2. The Python Language Reference — The import system — Python Software Foundation
  3. Distribution package vs. import package — Python Packaging Authority
  4. Install packages in a virtual environment using pip and venv — Python Packaging Authority

EliExplains lessons are original prose written from the open, credible references above. See Copyright & Licensing.

Researched 2026-08-19

Educational content only. It is not medical, legal or professional advice. Found an error? Tell us.