Think about it – you’re going to write possibly thousands, if not hundreds of thousands lines of code for a particular Python solution. You could write all these lines of code in one file and run it as a script. However, too many problems arise with that kind of setup.

Writing all your Python program code in one file

  1. Is not maintainable
  2. Finding errors and debugging your code is very hard
  3. Overall, it is a bad practice and would lead to spaghetti code

A practical approach is to divide your Python program file into many files. Besides, you can also keep highly related files in their own directories. Thus, you create modules that are inside packages for your Python program.

With that,

  1. You can follow one of the best practices.
  2. You are able to make the future you and other programmers happy when they read and review your code.
  3. You can produce maintainable and debuggable Python code.

When you do start implementing the use of modules and packages in your code, you will start to realize a weird file that gets created automatically by popular IDEs such as Pycharm. This file is the __init__.py file.

Besides, you may encounter some errors when importing your packages’ modules, functions, and classes. With a little research, you realize that you need to create the __init__.py file in the directories you want to keep a few modules of your program.

So,

What is __init__.py in Python?

An __init__.py file is required to make Python treat directories containing the file as packages. So, you can import all the sub-packages; modules; variables, functions, and classes within the modules using less and simpler code.

Besides, __init__.py file prevents directories with a common name from unintentionally hiding valid modules that occur later on the module search path or in subdirectories.

Thus, after creating __init__py file, you can be able to do,

  1. from package.module import * or
  2. from package.module import function or
  3. from package.subpackage.module import function, or
  4. from package import *

Generally, the __init__.py file works similarly to the __init__ class method. As you may know, the __init__ method in a class loads all the instance variables of each object created in your program.

For example, a class Student, which acts as a blueprint for creating student objects, can have student_name, subject_taking, age, e.t.c, as the instance variables. Thus, each student object created from the class can have unique values different from each other.

So, student1 can have

student1 = Student("Penelope", "Mathematics", 20)

Student2 can have

student2 = Student("Mary", "English", 19)

And so on.

In the case of our __init__.py file, it is used to load all the modules, functions, and classes that are known to each package. Therefore, you can use the package’s functionality across your Python code even when you use the asterisk * approach to import your modules.

Example implementation/use of __init__.py file in Python

Take this instance into account

You want to import a module or use a function within a file that is in a different directory. Thus, you would use a syntax similar to this: import package.

Then, you would access the functions and classes in the following syntax: package.file_with_the_class.class or package.file_with_the_function.function.

With an actual example of the instance above, let’s implement it and see how Python reacts.

Create a directory in your Desktop folder or anywhere you may want. Name it project_init or anything.

mkdir ~/Desktop/project_init                                                                                                           

Navigate inside the directory and create a main.py file.

cd project_init && touch main.py

Create a new directory that will act as our package. Create it in the current working directory that you are navigated into, project_init. Name it, first_package.

mkdir ~/Desktop/project_init/first_package                                                                                                           

Create two .py files that will act as our modules and host variables, functions, classes, e.t.c.

Name the files, module_1 and module_2

touch ~/Desktop/project_init/first_package/module_1.py 

touch ~/Desktop/project_init/first_package/module_2.py                                                                                                                                                                                                                     

Inside module_1.py file, create a simple function that prints the words “It is working, cap’n”


def check():
    print("It is working cap'n")

Now, try to import the function check() from module_1 and use it in your main.py file and run it.

In your main.py

import first_package

first_package.module_1.check()

Execute main.py file

python main.py  

What do you get?

Well, Python should throw an error that look like this:

Traceback (most recent call last):
  File "/home/hoofhoof/Desktop/project_init/main.py", line 3, in <module>
    first_package.module_1.check()
AttributeError: module 'first_package' has no attribute 'module_1'

It seems like our package does not have the module, module_1 although we created the file. Python doesn’t recognize the modules and the files inside.

There are two possible solutions to the problem above

  1. Explicitly import the function
  2. Use the __init__.py file so that it loads and registers all the modules, functions, and classes inside our package, first_package

Solution 1: Directly import the function and use it in our main.py file

Edit your main.py file to look like this:

from first_package.module_1 import check 

check()

Then rerun our main.py file.

python main.py

We shouldn’t have the problem.

It is working cap'n

If you have noticed, the approach can get really messy, especially if you have too many packages, modules, and functions/classes/variables you wish to import.

The main.py file will get cluttered. The goal was to declutter each Python file and deploy specific functionality to each file rather than write messy code.

So, we opt for another approach, which is using the __init__.py file.

Solution 2: Use __init__.py file to load all the modules inside our package

Without __init__.py file, you cannot import modules from another folder into your project. Revert the main.py file to the old code that produced errors when we imported our check() function.

import first_package

first_package.module_1.check()

Inside the first_package directory, create an __init__.py file to instruct Python to recognize the directory as a package.

touch first_package/__init__.py 

Well, if you run the main.py this time without changing the code that produced errors, it should execute successfully.

And voila!

It is working cap'n

However, if we keep using the approach above, we will have to repeat module.function_name or module.classname in our main.py. Still, the approach is not brief- if we have too many modules, it could clutter our main.py file, but we can improve it further.

We can import the whole module into our main.py file and use all the variables, functions, and classes. But we will create the same problem we created when we tried importing all the modules in our package.

Change your main.py file to:

# import the module so that we can use all the variables/functions/classes in it

import first_package.module_1

# try using our function
check()

Run the main.py file

python main.py

Oops! we got another error. Python cannot find our function, although it is defined in our module, module_1.

Traceback (most recent call last):
  File "/home/hoofhoof/Desktop/project_init/main.py", line 3, in <module>
    check()
NameError: name 'check' is not defined

Solutions to Python not loading all the functions/variables/classes in a module?

Solution 1: Directly import our function in our main.py file.
from first_package.module_1 import check

# try using our function
check()

If you run it, Python should not throw an error.

It is working cap'n


However, the approach would still mess up our main.py file. A better approach is to use our __init__.py file to load all the functionality found in our module to the main program.

Solution 1: Directly import our function in our main.py file.

Well, we can use the same __init__.py file to instruct Python to recognize the variables, functions, and classes inside our module, module_1. Here’s how to do that.

Revert to the previous code that produced a NameError when we tried to use a function declared in our module, module_1.

# import the module so that we can use all the variables/functions/classes in it

import first_package.module_1

# try using our function
check()

Edit your __init__.py file and directly instruct Python that you want to use the functions and classes inside the specific modules in our Python package.

So, in __init__.py file:

 from .module_1 import check

Then, change your main.py file to import all the functions or modules loaded using the __init__.py file.

from first_package import *

# try using our function
check()

Execute the main.py file, and voila!

It is working cap'n

The program is working with a more concise and maintainable code. Thus, you can manage all your imports inside your __init__.py file and focus on writing specific functionality for your main.py file.

You can use other functions, classes, and variables within a particular module by loading them using the __init__.py file.

Besides, you can load other modules and their functionalities inside the __init__.py file and use them in your main.py program.

In your __init__.py file


from .module_1 import check

# You can import other functionalities within other modules here
from .module_2 import check_from_module_2

Use another function in your main.py file by adding only one line of code.

from first_package import *

# try using our function
check()

check_from_module_2()

Run the program and the results:

It is working cap'n
It is working cap'n from module_2

The final alternative is to use the __all__ namespace variable to load all the modules within a package inside the __init__.py file.

The approach of using __all__ variable provides an explicit index of the package. The import statement looks at the __init__.py code defining a list named __all__. It takes the list as the list of module names that should be imported when from package.module import * syntax is encountered.

The __init__.py file of a package should contain the __all__ variable that follow the syntax: __all__ = [‘module1’, ‘module2’, ‘module3’]. This is the best practice. A developer is able to keep on updating __all__ whenever they have instances of from package import * used in their code.

Here is an example

Edit your __init__.py file and update it to reflect this:

# load all the modules inside our package
__all__ = ["module_1", "module_2", "module_3"]

We can then access these modules’ functionalities in our main.py file by importing the variables, functions, and classes from them.

from first_package import *

# function from module_1
module_1.check()

# another functionality from module_2 used here
module_2.check_from_module_2()

Results:

It is working cap'n
It is working cap'n from module_2

[In Summary]

What is the use of the file __init__.py in a package?

Python __init__.py file is an essential file needed to turn directories into packages and sub-packages. These packages contain modules that have variables, functions, and classes that you can use in your Python code.

The goal of separating Python program into separate files and packages with designated functionality helps programmers develop maintainable, easy-to-read, and debuggable code.

A regular package in Python is generally created by adding an __init__.py file. The __init__.py file can contain a few lines of import statements and the __all__ variable that contains a list of all the module names in the package’s namespace.

__init__.py file executes initialization code for the package to load all the names that can be imported into the package’s namespace.

What is the use of the file __init__.py in a package even when it is empty?

__init__.py file can also be initialized as an empty and be used to achieve the functionality of realizing a regular package. If the __init__.py file is empty, you can use anything across your package modules and their functionality.

If it is not empty, you can add the __all__ variable to the __init__.py file to limit the modules imported when you use an asterisk to import (from package import *) in other parts of your codebase. Thus, it lets the Python interpreter know that a directory contains code for a Python module or modules.

When you apply Python __init__.py best practices, it

  1. Allows you to import all the submodules using the from package.module import * syntax without encountering import errors. It mitigates errors that may arise when programmers use the star (*) syntax, even when a directory is not registered as a Python package.
  2. Allows Python to go deeper into the filesystem, find all the submodules present in that package, and import them all.
  3. Allows you to import modules, functions, variables, and classes easily. Contrary to what would be costly in terms of time needed to import sub-packages and modules in every package. Besides, importing some sub-modules directly might have unwanted side effects.

Conclusion

Well, that’s pretty much it. We have covered what the __init__.py file is, its application, and how it works like the instance method __init__. I hope I have guided you well. If you haven’t, ask me questions. Otherwise, read the article a few times if it doesn’t stick the first time.

Crack on!

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *