Skip to content

A Comprehensive Guide to Importing Modules in Python

Updated: at 04:45 AM

Importing modules is a fundamental concept in Python programming that allows you to access code from other files and packages. Modules encapsulate related code into reusable and organized units that can be shared across different scripts and programs. The import statement is used to bring modules into the current namespace so their attributes, classes, functions and other objects can be utilized.

In this comprehensive guide, we will cover everything you need to know about importing modules in Python, including:

Table of Contents

Open Table of Contents

Overview of Modules and Packages in Python

In Python, code is organized into logical files called modules. Each module contains definitions and statements related to a specific topic, keeping code compartmentalized and modular.

Some key facts about Python modules:

A Python package is a collection of related modules in a folder structure that defines a namespace. Packages allow hierarchical organization of modules.

So in summary, modules encapsulate Python code for reuse, while packages organize and namespace related modules. We will focus specifically on importing modules in this guide.

The import Statement Syntax

The main mechanism for accessing the contents of a module in Python is the import statement. Here is its basic syntax:

import module_name

This imports the target module and makes its contents available in the current namespace.

Some things to note about import:

Let’s see a simple example importing a module:

# Import module
import mymodule

# Access a function from the imported module
mymodule.say_hello()

# Access a constant variable
print(mymodule.MODULE_NAME)

This demonstrates the core functionality of import - making a module’s code available for use in the current program.

Now let’s explore some more advanced import techniques and syntax variations.

Importing Module Attributes Directly

When importing a module, you can directly access its attributes using the module name dot notation described above:

import mymodule

mymodule.say_hello()
x = mymodule.some_value

This allows your code to explicitly call out where attributes come from, making the source clear.

However, you can also set up imports so attributes are directly available without the module name prefix, like so:

from mymodule import say_hello, some_value

say_hello()
print(some_value)

Here we demonstrate from import syntax, which we will cover in more detail later. This imports the specific say_hello() function and some_value variable directly into the global namespace.

In general, directly importing attributes is handy for commonly used functions or constants. But namespace pollution can occur if overused.

Import Aliasing with as

When importing a module, you can specify an alias using the as keyword:

import mymodule as mm

mm.say_hello()

This allows you to rename the module reference to something shorter or more convenient.

Aliasing is also useful when importing multiple modules that have conflicting attribute names:

import pandas as pd
import matplotlib.pyplot as plt

Here we alias pandas to pd and matplotlib to plt to avoid overlap.

So import aliasing with as provides control over the namespace and prevents naming collisions.

Importing Multiple Modules on One Line

It’s common to need functionality from several different modules. Instead of separate import statements, you can import multiple modules on one line like this:

import module1, module2, module3

Or with aliases:

import pandas as pd, numpy as np, scipy as sp

This is convenient for reducing code clutter and importing related modules together.

Keep in mind it can reduce readability compared to one module per line. Also, if a module import fails, it will produce an error and stop further imports on that line.

Importing All Objects from a Module with *

You can import all attributes of a module using the * syntax:

from mymodule import *

This imports all objects defined in mymodule directly into the current namespace. This can be useful for modules that provide many useful attributes that you frequently access.

However, importing all module contents has downsides:

So in general, importing specific objects is preferred for clarity and tooling support.

Importing Specific Objects from a Module

For finer control over what’s imported from a module, you can specify individual objects.

The basic syntax is:

from module_name import object1, object2, ...

For example:

from math import cos, pi

print(cos(pi))

This imports just the cos() and pi attributes from the math module.

You can import objects into an aliased module name using:

from module_name import object1 as name1, object2 as name2

Advantages of selectively importing objects:

This provides precision control over what’s imported from a module.

Using from module import Syntax

The from module import syntax shown above is very convenient for importing specific module contents. Here are some key points:

Overall, from import provides fast access to just the objects you need from a module. But overuse can lead to namespace issues, so it should typically be constrained to selective imports.

Managing Module Namespaces with as

As mentioned above, when importing module objects directly, name collisions can occur due to lack of namespacing.

For example:

from module1 import my_function
from module2 import my_function

This results in an error due to duplicate my_function names.

To avoid this, we can import the objects into differently named namespaces using as:

from module1 import my_function as mf1
from module2 import my_function as mf2

Now the functions are uniquely named and import properly.

This technique is highly recommended when importing objects directly to prevent overlaps.

Relative Imports

When modules are structured as part of a package, you can use relative imports to access sibling modules at the same level.

For example, consider a mypackage package with modules module1.py, module2.py, and main.py:

mypackage/
   module1.py
   module2.py
   main.py

Inside main.py, we can import module1 using a relative import:

from . import module1

The . indicates look for the module in the same package directory rather than on the normal path.

Some key points about relative imports:

When leveraged properly, relative imports provide a clean way to access internally defined modules in a structured, encapsulated manner.

Importing Modules from Package Subdirectories

Larger packages often split up modules into subdirectories to organize related code.

You can import modules located in package subdirs using dot notation in the from statement:

from .subpackage1 import module1
from .subpackage2.module2 import func2

This allows arbitrary directory structures to be represented in a modular, importable way.

Some key points:

Overall, importing subdirectory modules helps reduce code duplication and allows large packages to segment code logically.

Importing Built-in and Third-Party Modules

Beyond your own modules and packages, Python comes batteries included with many built-in modules available right out of the box, such as math, random, datetime, and many more.

You can import built-in modules just like your own:

import math
import random
import datetime

Additionally, there is a vast ecosystem of third-party packages on PyPI that can be installed and imported:

import pandas
import matplotlib
import scipy

Some key points about external modules:

Leveraging built-in and third-party modules helps reduce reinventing the wheel while building on mature, well-tested Python codebases developed by the community.

Module Caching and Reloading

Python caches previously imported modules and reuses them on subsequent imports rather than reloading. This improves performance by only executing the code once.

Caching does have implications you should be aware of:

To force reloading, use imp.reload(module) or simply reload(module) in Python 2.x. But take caution, as this can lead to unpredictable behavior for already loaded modules.

Understanding import caching helps explain module reloading and when repeated imports reference the same object.

Using if __name__ == '__main__'

A common practice in reusable modules is using a code block like:

if __name__ == '__main__':
   # code here

This allows the module to execute more code when run directly vs imported.

The __name__ variable is set to:

This can be used to include test code, demo routines, or anything else that shouldn’t execute on import.

Placing imports, constants, function/class definitions outside this block allows them to be reused when the module is imported.

Proper use of if __name__ == '__main__' provides encapsulation and reusability of modules.

Finding Modules and Reading Documentation

As you utilize more modules in your code, here are some tips for finding and learning about them:

Gaining visibility into available modules along with reading docs helps familiarize yourself with Python’s extensive set of code reuse options.

Handling ImportErrors and Module Troubleshooting

When importing modules, ImportError exceptions can occur for several reasons:

Some troubleshooting tips:

Carefully handling import issues leads to robust code able to gracefully recover when module dependencies are not met.

Conclusion

We have covered a wide range of techniques for importing modules and packages in Python. Here are some key takeaways:

With structured use of modules and packages, you can write Python programs that are well-organized and leverage code reuse rather than reinventing the wheel. Mastering these import techniques will help set you on the path to efficiently developing robust and maintainable Python software applications.