Is __init__.py not required for packages in Python 3.3
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
Starting with Python 3.3, a directory can sometimes act as a package even if it does not contain __init__.py. That change came from implicit namespace packages. But "not required" does not mean "never useful" or "always optional." In many projects, __init__.py is still the right file to include.
What Changed in Python 3.3
Before Python 3.3, the normal rule was simple: if you wanted a directory to be importable as a package, that directory needed an __init__.py file.
Python 3.3 introduced implicit namespace packages. With that feature, Python can treat matching directory names on the import path as parts of one logical package even when they do not contain __init__.py.
That means this can now work in some cases:
And then:
The absence of __init__.py no longer automatically blocks the import.
What a Namespace Package Is
A namespace package lets multiple directories contribute to the same package name. This is useful when a logical package is spread across different distributions or locations on sys.path.
For example, imagine two different installed distributions both contributing under the same top-level package name:
Python can treat both company directories as parts of one namespace package, allowing imports like:
That is the main motivation for the feature.
When __init__.py Is Still Useful
Even though it is no longer always required, __init__.py still matters when you want package-level behavior.
Typical reasons to keep it include:
- marking the package explicitly for clarity
- running package initialization code
- defining
__all__ - re-exporting selected names
- avoiding accidental namespace-package behavior
Example:
Without __init__.py, there is no package file in which to place that logic.
A Simple Example
Suppose you have:
And formatter.py contains:
In Python 3.3 and later, you may be able to import it without tools/__init__.py:
That works because tools can be treated as an implicit namespace package.
Why Many Projects Still Include It
In real projects, adding __init__.py often makes intent clearer and avoids surprises in tooling, packaging, and imports. Namespace packages are powerful, but they are also more implicit.
If your package is a normal single-directory package inside one application, __init__.py is still a sensible default. It makes the package explicit and gives you a place for package-level exports.
In other words:
- namespace packages are useful when you need them
- ordinary packages with
__init__.pyare still perfectly normal
One Important Distinction
"Not required" is not the same as "ignored." If __init__.py exists, Python treats the directory as a regular package, not an implicit namespace package.
That distinction matters because regular packages and namespace packages differ in behavior and use cases. Namespace packages are designed for composition across multiple paths. Regular packages are a single defined package with an actual package module file.
Practical Guidance
Use implicit namespace packages when:
- multiple separately distributed components should share a package namespace
- you intentionally want package composition across multiple locations
Use __init__.py when:
- the package is ordinary and self-contained
- you want explicit package structure
- you need package initialization or exports
- you want to reduce ambiguity for humans and tools
For most application codebases, including __init__.py is still the simpler choice unless you have a reason not to.
Common Pitfalls
- Interpreting Python 3.3's change as "never use
__init__.pyagain." The file is still useful and common. - Forgetting that namespace packages exist for a specific composition use case, not as a universal replacement.
- Expecting package-level initialization to work without
__init__.py. There is no file to execute in that case. - Mixing regular-package and namespace-package assumptions in the same codebase without understanding the difference.
- Blaming import issues on Python alone when packaging layout or
sys.pathsetup is the real cause.
Summary
- Python 3.3 introduced implicit namespace packages, so
__init__.pyis no longer always required. - A directory without
__init__.pycan still be importable as a package in the right context. - '
__init__.pyremains useful for initialization, exports, and explicit package structure.' - Namespace packages are most useful when a package spans multiple directories or distributions.
- For ordinary self-contained packages, including
__init__.pyis still often the clearest choice.
Related reading
- Is a Python dictionary an example of a hash table?
- Is a Python list guaranteed to have its elements stay in the order they are inserted in?
- Is arr.__len__ the preferred way to get the length of an array in Python?
- Is False 0 and True 1 an implementation detail or is it guaranteed by the language?
- Is generator.next visible in Python 3?
- Is it a good practice to use try-except-else in Python?
- Is it bad to have my virtualenv directory inside my git repository?
- Is it not possible to define multiple constructors in Python?
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.