Import statements are commonplace in Python projects with many files.
Imports may be difficult to understand, even for Python developers with experience working on several projects. If you’re here, it’s presumably because you want to know more about imports in Python, and in particular about absolute and relative imports.
This guide will teach you how the two are distinct and will discuss the benefits and drawbacks of each. Come on, let’s get in.
in!
A Quick Recap on Imports
Python module and package knowledge is helpful for comprehending imports. A Python module is any file with the.py suffix, and a Python package is any folder that includes modules (or, in Python 2, any folder that has a __init .py file).
Problems arise when one module wants to use features available in another module or package. Bringing in
it!
How Imports Work
Okay, but how do imports really function? Assume you are importing module abc, which looks like
so:
import abc
Python will initially check sys.modules for the module with the name abc. What you’re looking at is a history of all imported modules.
If Python can’t find a module with that name in its cache, it will go through its preinstalled ones. They are part of Python’s standard installation and may be accessed using the Python Library. Python then looks in the directories specified by sys.path if the name isn’t found in the preinstalled modules. The currently active directory is included in this list and is often the starting point for any such investigation.
Python assigns the module to a name in the current context after it locates it. With this change, using abc inside the current file no longer results in a NameError.
A ModuleNotFoundError will be returned if the specified name cannot be located. Imports are explained in detail in the Python reference manual, which you may get here. Warning: Safety Issues
It’s important to keep in mind that Python’s import mechanism has several major security flaws. Adaptability is a major factor in this. This includes the ability to write to the module cache and replace built-in Python features through the import mechanism. Threats to the security of your application might also come from using third-party packages.
For additional information on these security issues and possible solutions, check out the following articles and links.
them:
-
10 common security gotchas in Python and how to avoid them
by Anthony Shaw (Point 5 talks about Python’s import system.) -
Episode #168: 10 Python security holes and how to plug them
from the TalkPython podcast (The panelists begin talking about imports at around the 27:15 mark.)
Syntax of Import Statements
To further your understanding of import statements, let’s go into their syntax. Packages and modules may both be imported. It is possible to import just certain objects from a module or package (note that importing a package is similar to importing the module’s __init .py file).
As a rule, you’ll encounter one of two distinct import syntaxes. The first method involves a direct import of the material, such as
this:
import abc
Package or module abc is ok.
With the second form, the resource is imported from another package or module. This is an example of
example:
from abc import xyz
xyz can be anything from a package to a class to a function.
To further customise your import, you may rename any resource that has been imported.
so:
import abc as other_name
The script will internally rename the imported resource abc to other name. It’s now required to be referred to by its new name, other name.
recognised.
Styling of Import Statements
The Python official style guide, PEP 8, includes some advice for crafting effective import statements. Listed below is a
summary:
-
Imports should always be written at the top of the file, after any module comments and
docstrings
. -
Imports should be divided according to what is being imported. There are generally three groups:
- standard library imports (Python’s built-in modules)
- related third party imports (modules that are installed and do not belong to the current application)
- local application imports (modules that belong to the current application)
-
Each group of imports should be separated by a blank space.
It’s also a good idea to alphabetize your imports into their respective categories. When there are several imports in a file, this makes it much simpler to locate a certain import.
This is a sample of import formatting:
statements:
"""Illustration of good import statement styling.
Note that the imports come after the docstring.
"""
# Standard library imports
import datetime
import os
# Third party imports
from flask import Flask
from flask_restful import Api
from flask_sqlalchemy import SQLAlchemy
# Local application imports
from local_module import local_class
from local_package import local_function
There are three unique sections separated by whitespace in the preceding import declarations. Moreover, inside each category, they are arranged alphabetically.
group.
Absolute Imports
You now know the ins and outs of crafting import statements in a professional manner. The moment has come to get a deeper understanding of absolute imports.
Absolute imports identify the target resource by their whole path from the project’s root.
folder.
Syntax and Practical Examples
The following directory, for example,
structure:
└── project
├── package1
│ ├── module1.py
│ └── module2.py
└── package2
├── __init__.py
├── module3.py
├── module4.py
└── subpackage1
└── module5.py
Project is the parent directory, and it has two children: package1 and package2. Both module1.py and module2.py may be found in the package1 folder.
Two modules, module3.py and module4.py, and an initialization file, __init .py, are located in the package2 directory. There’s also a file called module5.py in the subpackage directory.
Assume for the moment that
following:
-
package1/module2.py
contains a function,
function1
. -
package2/__init__.py
contains a class,
class1
. -
package2/subpackage1/module5.py
contains a function,
function2
.
These are some real-world applications of absolute
imports:
from package1 import module1
from package1.module2 import function1
from package2 import class1
from package2.subpackage1.module5 import function2
It is important to remember that you must provide the full path to every package or file, starting with the package root folder. This is identical to its file path, except instead of a slash (/), we use a dot (. ).
).
Pros and Cons of Absolute Imports
It is recommended to utilise absolute imports since they are easy to understand. Looking at the statement, you can immediately identify the location of the imported resource. What’s more, absolute imports are always effective, regardless of where the import statement is now located. Moreover, absolute imports are encouraged under PEP 8.
Nonetheless, absolute imports may get extremely verbose at times due to the intricacy of the directory structure. Picture yourself with a sentence like
this:
from package1.subpackage2.subpackage3.subpackage4.module5 import function6
To put it mildly, that’s ludicrous. Fortunately, in these cases, relative imports may serve as a viable
cases!
Relative Imports
By using an import statement, the resource to be imported is specified relative to the current position. Implicit and explicit relative imports exist. Due to its deprecation in Python 3, I will not be discussing implicit relative imports.
here.
Syntax and Practical Examples
Both the current working directory and the directory containing the module, package, or object to be imported affect the syntax of a relative import. Some instances of relative clauses include
imports:
from .some_module import some_class
from ..some_package import some_function
from . import some_class
Each import statement up top has at least one dot, as you can see. Dot notation is used to indicate position in relative imports.
If there is just one dot after a module or package name, it is because it is in the same directory. If there are two dots before a directory name, it is in the parent directory of the current working directory. If there are three dots, it means that it is in the parent directory, and so on. If you’re comfortable with a Unix-like OS, you’ll recognise this immediately!
So long as your directory structure is the same as
before:
└── project
├── package1
│ ├── module1.py
│ └── module2.py
└── package2
├── __init__.py
├── module3.py
├── module4.py
└── subpackage1
└── module5.py
Remember the record
contents:
-
package1/module2.py
contains a function,
function1
. -
package2/__init__.py
contains a class,
class1
. -
package2/subpackage1/module5.py
contains a function,
function2
.
The package1/module1.py file may be updated to include the import of function1 in this
way:
# package1/module1.py
from .module2 import function1
Since module2.py is located in the same folder as module1.py, just one dot is needed.
In the package2/module3.py file, you may import class1 and function2.
way:
# package2/module3.py
from . import class1
from .subpackage1.module5 import function2
The first import line has a single dot, which indicates that class1 is being imported from the currently active package. Keep in mind that when you import a package, you’re really just loading the __init .py file inside of that package as a module.
Since subpackage1 is located in the same directory as the current module (here, module3.py), you would use a single dot once again in the second import line.
.
Pros and Cons of Relative Imports
Relative imports clearly have the benefit of brevity. The absurdly lengthy import statement you saw previously may be shortened to something as simple as
this:
from ..subpackage4.module5 import function6
As a result, relative imports may be a tangled mess, especially in collaborative projects where the directory structure is subject to change. Relative imports are less readable than absolute imports since it’s not clear where the imported files are stored.