
In this lecture, we will explain the role of __init__.py, which is essential for organizing the structure of Python packages.
We will also clarify topics that often confuse beginners, such as the behavior of import * and the usage of __all__, using concrete examples.
Table of Contents(目次)
What Is __init__.py? Understanding the Basic Structure of Python Packages
__init__.py is a special file that tells Python “this folder is a package.”
For example, consider the following structure:
project/
├─ main.py
└─ my_package/
├ __init__.py
├ module_a.py
└ module_b.py
The presence of __init__.py inside my_package/ allows the following imports written in main.py:
import my_package.module_a
from my_package import module_b
If __init__.py does not exist, Python treats the folder as “just a directory” and does not recognize it as a package.
Why __init__.py Became Optional in Python 3.3+: The Concept of Implicit Namespace Packages
Strictly speaking, Python 3.3 and later includes a mechanism called Implicit Namespace Packages, allowing a folder to function as a package even without __init__.py. However, this is mainly for advanced use cases, and many tools (linters and IDEs) assume the presence of __init__.py. Therefore, for readability and compatibility, adding this file is strongly recommended.
What Should You Write in __init__.py? Fundamentals and Practical Examples
Please download the following file and check the contents inside each file:
The contents of __init__.py may be completely empty. However, as a project grows, it is increasingly common to include initialization logic or convenient export settings within the file.
Organizing a Package's Public API Using __init__.py
For example, frequently used classes or functions can be gathered here so that the package can present a clean and unified interface.
# __init__.py
from .module_a import func_a
from .module_b import ClassB
This allows external files (like main.py) to access them in a simple manner:
from my_package import func_a, ClassB
How __init__.py Influences the Import Mechanism
from my_package import func_a, ClassB works due to the following sequence of operations:
- The moment you write
from my_package, the__init__.pyinsidemy_packageis executed. - Inside
__init__.py, the statementsfrom .module_a import func_aandfrom .module_b import ClassBrun, exposingfunc_aandClassBas attributes of themy_packagenamespace. - As a result,
main.pycan simply writefrom my_package import func_a, ClassBand import them directly.
How to Use __all__: Controlling import * Safely
When writing code inside __init__.py, the special variable __all__ becomes important. __all__ controls which symbols (functions, classes, variables, etc.) are exported when executing from package import *.
The wildcard * means “everything,” but it does not actually import every module inside the package automatically.
If __all__ is not defined, import * imports the following:
- Variables, functions, and classes defined directly inside
__init__.py. - Names imported inside
__init__.pywhose names do not start with an underscore (_).
Without defining __all__, internal or intermediate variables may be unintentionally exposed, potentially polluting namespaces in importing code or introducing unexpected bugs.
By defining the list variable __all__, you can explicitly control which names (symbols) will be exported when import * is used. This prevents unintended imports and greatly improves both the maintainability and the clarity of the package’s API.
# __init__.py
from .module_a import func_a
from .module_b import ClassB
__all__ = ['func_a', 'ClassB']
Now, even when using wildcard import, only func_a and ClassB will be imported:
# main.py
from my_package import *
func_a()
obj = ClassB()
Writing Initialization Logic in __init__.py
Another use case of __init__.py is writing initialization logic that executes when the package is loaded.
For example, the message/__init__.py in fortune_cookie can register messages used for language selection.
# message/__init__.py
PROMPT_SELECT_LANGUAGE = 'Please select your language (jp/en): '
This can be called from fortune.py as follows:
# fortune.py
import message
lang_code = input(message.PROMPT_SELECT_LANGUAGE)
print(lang_code)
Summary: Best Practices for Using __init__.py
Finally, let’s summarize the best practices for organizing package structures.
- Always place an
__init__.pyfile in every package. - Import frequently used functions and classes inside
__init__.pyso users do not need to know the internal structure. - Define
__all__to explicitly control which APIs are exposed externally. - Keep initialization logic minimal and maintain a clean structure.
By following these practices, the overall clarity and maintainability of your package design will improve significantly.





