4.5 KiB
title, created, tags, category, status, up, related, source, author, published
| title | created | tags | category | status | up | related | source | author | published | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| What is __init__.py? | 2026-05-22 |
|
python_note | reference | project/index |
|
What is __init__.py?
__init__.py is the file that tells Python "this folder is a package". When you put it inside a directory, that directory becomes importable like a module.
The Core Purpose
Without __init__.py (in older Python, ≤3.2), a folder was just a folder — Python could not import from it. With it, the folder becomes a package you can do this with:
from recipe_scraper.scraper import fetch_recipe
Here, recipe_scraper/ is a package because it contains __init__.py.
Note: Since Python 3.3, "namespace packages" allow imports without
__init__.py, but regular packages still use it because it gives you more control (init code, explicit exports, IDE/tooling support).
What It Does in Practice
1. Marks the folder as a package
Even an empty __init__.py is meaningful. It signals to Python:
"Treat this directory as something you can import from."
2. Runs initialization code
Anything inside __init__.py runs the first time the package is imported. This is useful for:
- Setting up logging
- Loading config
- Registering plugins
# recipe_scraper/__init__.py
import logging
logging.getLogger(__name__).addHandler(logging.NullHandler())
3. Controls the package's public API
You can re-export things so users don't need to know the internal file layout:
# recipe_scraper/__init__.py
from .scraper import fetch_recipe
from .parser import parse_recipe
from .db import save_recipe
__all__ = ["fetch_recipe", "parse_recipe", "save_recipe"]
Now consumers can write the short form:
from recipe_scraper import fetch_recipe # clean
# instead of:
from recipe_scraper.scraper import fetch_recipe # verbose
4. Defines package metadata
A common pattern is exposing a version string:
# recipe_scraper/__init__.py
__version__ = "0.1.0"
How It Fits the Recipe Scraper Project
Given the folder structure from Recipe Web Scraper - Getting Started:
recipe-scraper/
├── pyproject.toml
└── recipe_scraper/
├── __init__.py ← makes this a package
├── scraper.py
├── parser.py
├── db.py
└── cli.py
The __init__.py here lets you:
- Run
poetry run python -m recipe_scraper.cli— only works becauserecipe_scraperis a package. - Import cleanly from anywhere in the project:
from recipe_scraper.db import Recipe - Optionally expose a tidy top-level API:
So users of your library can just do:
# recipe_scraper/__init__.py from .scraper import scrape_url from .db import Recipe, init_db __version__ = "0.1.0" __all__ = ["scrape_url", "Recipe", "init_db"]import recipe_scraper recipe_scraper.scrape_url("https://...")
When to Leave It Empty vs. Fill It
| Situation | What to put in __init__.py |
|---|---|
| Internal-only package, no public API | Empty file |
| You want a clean import surface | Re-exports + __all__ |
| Library shipped to PyPI | __version__, re-exports, maybe logging setup |
| One-time setup needed (config, env) | Initialization code at the top |
Rule of thumb: start with an empty __init__.py. Only add code when you have a concrete reason — re-exports, version, or setup. Don't put heavy logic in __init__.py; it runs on every import.
Common Gotchas
- Heavy imports slow everything down. If
__init__.pyimports a big library (e.g.,pandas), everyimport recipe_scraper.anythingpays that cost. Keep it light. - Circular imports often start in
__init__.py. If__init__.pyimports fromscraper.py, andscraper.pyimports from the package root, you get a cycle. Use lazy imports or restructure. - Tests need it too. A
tests/folder usually has an empty__init__.pyso pytest can discover test modules consistently (though pytest'srootdirconfig can avoid this).
TL;DR
__init__.py= "this folder is a Python package".- Can be empty — just its presence matters.
- Use it to re-export the public API, set
__version__, or run small setup. - Keep it light: every import of the package runs it.
Related
- Recipe Web Scraper - Getting Started
- poetry_guide — Poetry's
poetry newcreates this file automatically