What are Packages in Python and What is the Role of __init__.py files? (82/100 Days of Python)

Martin Mirakyan
4 min readMar 24, 2023

--

Day 82 of the “100 Days of Python” blog post series covering packages and __init__ files

In Python, the __init__.py file is a special file that serves several important purposes in a package. In this tutorial, we will explain what __init__.py files are, their meaning, and why they are needed in Python packages.

What is a package in Python?

Before diving into the details of __init__.py files, it's important to understand what a package is in Python. A package is a way to organize related modules (Python files) into a single, easy-to-use namespace. Packages allow you to group related functionality together, making it easier to organize and reuse your code.

A package in Python is simply a directory that contains a special file called __init__.py. The __init__.py file is executed when the package is imported, and it can contain any Python code you like.

What is the meaning of __init__.py files?

The __init__.py file has several meanings in Python. First and foremost, it is used to mark a directory as a package. When the Python interpreter encounters a directory that contains an __init__.py file, it treats the directory as a package and allows you to import modules from that package using the dot notation.

Secondly, the __init__.py file is used to initialize the package. This means that you can use the __init__.py file to set up any configuration or state that is needed by the package. For example, you can define package-level variables or import other modules that the package depends on.

Finally, the __init__.py file is used to control what symbols are exported from the package. When you import a module from a package, Python looks for the symbol in the module first, and then in the package's __init__.py file. This allows you to selectively import symbols from the package without cluttering up the namespace.

Why are __init__.py files needed?

__init__.py files are needed for several reasons. First and foremost, they allow you to organize your code into logical units called packages. This makes it easier to manage and reuse your code, and it also helps to avoid naming conflicts.

Secondly, __init__.py files are needed to control the import behavior of a package. By selectively importing symbols from a package, you can avoid name clashes and keep your code organized.

Finally, __init__.py files are often used to set up package-level configuration and state. This can include defining package-level variables or importing other modules that the package depends on.

Examples of __init__.py files

Here are some examples of how __init__.py files can be used in Python packages.

Defining package-level variables

# mypackage/__init__.py

# Define a package-level variable
__version__ = '1.1.42'

In this example, we define a package-level variable called __version__ in the __init__.py file. This variable can be accessed from any module in the package using the dot notation (mypackage.__version__). This is a common practice for library developers where they include the package version and some other metadata in the root of the package.

Importing modules into the package namespace

# mypackage/__init__.py

# Import the mymodule module into the package namespace
from . import mymodule

In this example, we import the mymodule module into the package namespace by using the dot notation (from . import mymodule). This allows us to access the contents of mymodule from any module in the package using the dot notation (mypackage.mymodule).

Defining a package-level function

# mypackage/__init__.py

# Define a package-level function
def my_package_function():
print('Hello from my_package_function!')

In this example, we define a package-level function called my_package_function in the __init__.py file. This function can be accessed from any module in the package using the dot notation (mypackage.my_package_function()).

Controlling what symbols are exported from the package

# mypackage/__init__.py

# Only export mymodule2 from the package namespace
from .mymodule2 import *
__all__ = ['mymodule2']

In this example, we use the __all__ variable to control what symbols are exported from the package. We import the mymodule2 module into the package namespace using the star notation (from .mymodule2 import *) and then set __all__ to a list of symbols that should be exported (__all__ = ['mymodule2']). This allows us to selectively import symbols from the package without cluttering up the namespace.

Important Things to Keep in Mind About __init__.py Files

  1. __init__.py files can be empty: You don't have to put any code in the __init__.py file if you don't need to. An empty __init__.py file is still necessary to mark a directory as a package, but it doesn't have to contain any code.
  2. __init__.py files can be used to perform setup actions: In addition to defining package-level variables and functions, you can also use the __init__.py file to perform setup actions for your package. For example, you might want to initialize a database connection or load configuration data.
  3. __init__.py files can be nested: If you have sub-packages within your package, you can include an __init__.py file in each sub-package as well. This allows you to define package-level variables and functions for each sub-package.
  4. __init__.py files can raise ImportError: If you need to perform some setup actions for your package, such as importing a required module, you can use the __init__.py file to do so. However, if the setup actions fail, you can raise an ImportError in the __init__.py file to prevent the package from being used.
  5. __init__.py files are not required in Python 3.3+: Starting with Python 3.3, you don't have to include an __init__.py file in your package directories. However, it's still a good practice to include one to ensure compatibility with older versions of Python.

What’s next?

--

--