We have fairly a good idea of how to use import statements. Now it is time to understand absolute and relative imports, especially when we are importing custom or project-specific modules. To illustrate the two concepts, let's take an example of a project with different packages, sub-packages, and modules, as shown next:
project
├── pkg1
│ ├── module1.py
│ └── module2.py (contains a function called func1 ())
└── pkg2
├── __init__.py
├── module3.py
└── sub_pkg1
└── module6.py (contains a function called func2 ())
├── pkg3
│ ├── module4.py
│ ├── module5.py
└── sub_pkg2
└── module7.py
Using this project structure, we will discuss how to use absolute and relative imports.
Absolute import
We can use absolute paths starting from the top-level package and drilling down to the sub-package and module level. A few examples of importing different modules are shown here:
from pkg1 import module1
from pkg1.module2 import func1
from pkg2 import module3
from pkg2.sub_pkg1.module6 import func2
from pkg3 import module4, module5
from pkg3.sub_pkg2 import module7
For absolute import statements, we must give a detailed path for each package or file, from the top-level package folder, which is similar to a file path.
Absolute imports are recommended because they are easy to read and easy to follow the exact location of imported resources. Absolute imports are least impacted by project sharing and changes in the current location of import statements. In fact, PEP 8 explicitly recommends the use of absolute imports.
Sometimes, however, absolute imports are quite long statements depending on the size of the project folder structure, which is not convenient to maintain.
Relative import
A relative import specifies the resource to be imported relative to the current location, which is mainly the current location of the Python code file where the import statement is used.
For the project examples discussed earlier, here are a few scenarios of relative import. The equivalent relative import statements are as follows:
• Scenario 1: Importing funct1 inside module1.py:
from .module2 import func1
We used one dot (.) only because module2.py is in the same folder as module1.py.
• Scenario 2: Importing module4 inside module1.py:
from ..pkg3 import module4
In this case, we used two dots (..) because module4.py is in the sibling folder of module1.py.
• Scenario 3: Importing Func2 inside module1.py:
from ..pkg2.sub_pkg_1.module2 import Func2
For this scenario, we used two dots (..) because the target module (module2.py) is inside a folder that is in the sibling folder of module1.py. We used one dot to access the sub_pkg_1 package and another dot to access module2.
One advantage of relative imports is that they are simple and can significantly reduce long import statements. But relative import statements can be messy and difficult to maintain when projects are shared across teams and organizations. Relative imports are not easy to read and manage.
0 comments:
Post a Comment