Wednesday, February 6, 2019

Stack Abuse: Relative vs Absolute Imports in Python

While you can put simple projects in a single file, most Python development projects will require multiple files to keep them manageable. That means you need a way to import one file into another. However, many Pythonistas find importing files confusing. Fortunately, it is easy if you know the difference between the various Python import statements.

What is Importing?

Importing refers to allowing a Python file or a Python module to access the script from another Python file or module. You can only use functions and properties your program can access. For instance, if you want to use mathematical functionalities, you must import the math package first. This is because you must define everything you want to use in Python before you use them.

For example, Python would give a NameError for the following code:

myPi = math.pi  

This is because neither the math object nor its properties and methods are natively available to the language itself. To use the math object, you must import it first.

import math

myPi = math.pi  
print myPi  

The import statement adds the object to the current scope of your program.

How Imports Work

The import statements do a lot under the hood to import file or module. First, they look for your module or package in sys.modules, where Python stores your previously imported code. If Python cannot find the module there, it will then search through the Python Standard Library for it. If Python still cannot find the module, it will go through your entire storage space, starting with the current directory and the ones listed in your system.path. If the module is found in these places, it will add the module to your program, otherwise, it will give a ModuleNotFoundError.

Import Statement Syntax

To import a module directly you just put the name of the module or package after the import keyword. Please note that this statement is case sensitive.

import mymodule  

However, Python does offer a more sophisticated syntax for importing code. This second format includes the from keyword as well.

from mypackage import mymodule  

In this format, you specify both the module or code you want along with where it is. You put the name of your code, module, or subpackage for mymodule, and its location for mypackage. Such an import statement is great if you only want to import some of the code from the mentioned package, and not the package itself.

You can even rename the module by including the as keyword.

import mymodule as oMyFunction  

You can also use the asterisk (*) as a wild card. The following statement will import every function and property contained in the math package.

from math import *  

Regardless of the syntax, you should always follow the recommended importing best practices.

Absolute Imports

Absolute imports include the entire path to your script, starting with the program's root folder. While you must separate each folder by a period, you can have it be as long as you need it.

The following are examples of absolute imports:

from package1.firstmodule import firstmodule  
import package1.secondmodule.myfunction  

Absolute Import Advantages and Disadvantages

Unlike other languages, most Python developers prefer using absolute imports over their relative cousins. This is because absolute imports make it really clear what you are trying to do. The actual location of your files is right there in your code. In fact, you can use them anywhere in your code. They will just work.

Absolute imports can get quite long though. If your project has sub packages in sub packages in sub packages, your import statements can expand beyond a single line of code. When that happens, you are much better off using relative imports instead.

You also may discover an issue when you start your program using different startup files. The Python interpreter only declares the starting file's current folder as its sys.path package root. This is fine if you only load your program using files from the root folder. This is because sys.path will remain static throughout your script.

However, the situation changes when you start your program from a subfolder, or in any other situation where your sys.path may change. Then, your "root folder" is the subfolder. Because you cannot use implicit imports (as we will see below), any file outside the subfolder becomes inaccessible to your program.

You have two workarounds for this. You can either start your subfolder script as an imported module or you can append sys.path directly in your code.

For example:

  • Importing modules as run time: python -m packA.a2
  • Append sys.path before importing your files:
import os, sys  
sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))  
from packA.subA import sa2  

Relative Imports

With relative imports, you only specify where your resources are relative to the current code file. You can do this either implicitly or explicitly, even though implicit relative imports were removed in Python 3.

As for the syntax, relative imports make use of dot notation. Single dots represent the directory of the current script. Two dots represent the parent folder. Thress dots mean the grandparent, and so forth. You might be familiar with this system if you use a UNIX-like operating system or the Windows console.

The following are examples of relative imports:

  • Explicit imports
import other  
from . import some_class  
from .subA import sa1  

  • Implicit imports
from .some_module import some_class  
import some_function  
import subA.sa1  

Relative Imports and their Advantages and Disadvantages

Relative imports rarely grow as long as absolute imports. They can even turn a ridiculously long absolute statement into something as simple as:

from ..my_sub_package.my_module import my_function  

However, they also hide the paths to your modules. This might be okay if you are the only developer, but it gets messy if you are a part of a development team where the actual directory structure can change.

Which Import to Use?

Unless you are working on a large project with several layers of sub-packages, you should always use absolute imports. That way, your code will be easily understood by anyone that looks at it, including yourself if you got back to it to update it later. Even if you do have long paths, you should still try to write your program to only use absolute statements to simplify your code and your life.

Conclusion

Like any other modern programming language, Python allows you to import code from other files or modules. However, this can turn in to a confusing and error-prone process, unless you understand the concepts behind the import system.

In this article we looked at the various ways of importing code in to our Python programs, including absolute and relative imports. We also compared the pros and cons of each, which have their advantages in different use-cases.



from Planet Python
via read more

No comments:

Post a Comment

TestDriven.io: Working with Static and Media Files in Django

This article looks at how to work with static and media files in a Django project, locally and in production. from Planet Python via read...