Clean Python: get rid of __init__.py

Piotr Włodarek
2 min readMay 31, 2022

TL;DR

Since Python 3.3 it is possible and practical to avoid __init__.py clatter and its implicit package initialization. Prefer the new namespace packages (no __init__.py) over regular packages (with __init__.py) where possible.

Rationale

The __init__.py was originally introduced to Python to explicitly mark directory as Python package. The intention was to avoid accidental override of Python builtin packages by random directories programmers may have in their projects (like maybe a “sys” or “os” directories). This is not a concern with new namespace packages because in case of conflict they have lesser priority and won’t override builtins.

The __init__.py marked packages (regular packages) are not deprecated and will continue to be fully supported. But it’s a good idea to clean up the code.

My first concern with __init__.py in each source directory is visual clutter. The sheer ugliness of it.

In practice, the more pressing problem is implicit and oftentimes surprising package initialization happening in __init__.py. No matter how long I code in Python, I still find myself puzzled by code hiding in these files, implicit timeline and order this code gets executed and unexpected side effects it causes. I prefer code to be called explicitly and predictably.

Are there any drawbacks to the new namespace packages? Not many. You can’t use the __name__ == “__main__” pattern but that was a bad idea anyway. Use tests to exercise your code instead. Some legacy development tools may rely on regular packages. For example, I had to add __init__.py aside pytest’s conftest.py files in sibling directories.

Summing up, Python significantly improved on its arguably biggest flaw, package/namespace system. Take advantage of this.

--

--