When our program becomes too large in size, we can place similar modules under one package. As we organize computer files in directories, for example, we keep all the images in the “photo” directory. This is similar to understand the concept of package.
If we want a steady hold of different data and files in any program, we can create a package(collection of modules).
1.1. Python packages by Example
Consider an example, there may be different sound file formats like .ailf, .wav, .avf, .mp3. In order to alter between various file formats, we may need to design and preserve such a growing package.
We may perform varieties of operations on sound data which includes mixing, create a stereo effect, add echo, and many more. For these operations, we will have to write a lot of streams of modules. But instead, we can use packages and their possible structure can be as follows.
sound/ => Top-main packageinit.py => Initialize the sound package
formats/ => Sub-package for conversion of different file formats
effects/ => Sub-package for different sound effects
filters/ => Sub-package for different filters
Note: This is just one possible structure and it will vary from project to project and also depends on the requirement of the particular problem.
When we import a package, Python searches through the sys.path directory to find the package subdirectory. Every directory must have a __init__.py named file or else python will not consider it as a package.
Lets take an example, we are developing a car.
1.2. Import a module from another Package in Python
So, if we want to import module tube.py from machine which exists in car package we can do it by the following example.
Example to import a module in python.
This loads the sub-module machine.tube from the package car.
It can be now be used to call function with parameters
So, now we have designed our own package called readytogo. We can test our package. Simply import the function module from the package.
from readytogo import mathematics
2. What is __init__.py?
__init__.py is a special file. This file is stored in every package folder. __init__.py has two characteristics:
The python interpreter will only recognize that folder as packages that contain the __init__.py file.
It also uncovers the specified resources from the imported module.
If we keep __init__.py file empty, then all the functions of the module will be available when the package is imported.
The __init__.py file is generally kept empty. But, we can declare specific functions from modules of the package in the file to make them ready for import.
from .mathematics import power
from .name import callname
The specified function will be imported to the interpreter session.
3. Import * from a package
The question may arise in our mind that what will happen if we write from car.machine import *? Is the statement correct? Normally, anyone will think that the program will go out of the filesystem and import all the submodules present in the package.
Well, to import all sub-modules it could take a lot of time and cause various unwanted effects. But, we have a solution, the solution is to arrange an explicit index of the package for every package author.
If we have a list __all__ for an __init__.py package, then the list of modules will be imported when from package import * is encountered. This list can be updated according to the new version of the packages.
For example, the file car/machine/__init__.py can contain:
So, from car.machine import * would import all the sub-modules of car.machine package.
Consider an example from sound package.
from sound.effects import *
Here, the echo and surround modules are imported individually in the current namespace in the first two lines respectively. But we can import all modules by the use of a single line from sound.effects import * as they are defined in the sound.effects package, so all modules and files will be imported when the from sound.effects import * statement is executed. (It will also work when __all__ is defined.)
4. Intra-package References
As we now know, we can structure packages into sub-packages. Suppose, the module sound.filters.equalizer wants to use echo module in the sound.effects package, it can do so by a statement from sound.effects import echo.
So, it means that a module can use or refer to other sibling packages and sub-packages.
Note: The relative import is dependent on the current module’s name. The name of the main module is always written as “__main__“, so the module in the program must use absolute imports.
5. Packages in multiple directories – use of __path__
__path__ is a special attribute or feature supported by python packages. It is initialized as a list that contains the name of all the directory which holds the package’s __init__.py before executing the code of that file.
We can modify the variable, which may affect the searches for sub-packages and other modules inside the package. However, this feature is not much used or needed.
By updating the __path__ we can force the interpreter to look in a different directory for modules belonging to that package.
This would allow us to, e.g., load different versions of the same module based on runtime conditions. We might do this if we wanted to use different implementations of the same functionality on different platforms.