How does the import module work in Python?

sharmapacific profile image Prashant Sharma Updated on ・4 min read

This post was initially shared on my blog.

The objective of writing this article is to develop a better understanding of how the import statement works and different forms of importing.

In Python, Whenever you want to import a module, you write as following -

import module_name

When you call import in the Python, the interpreter searches the module through a set of directories for the name provided and runs all of the code in the module file. The list of directories that it searches is stored in sys.path and can be modified during run-time.

Python’s documentation about sys.path as -

A list of strings that specifies the search path for modules. Initialized from the environment variable PYTHONPATH, plus an installation-dependent default.

Now let's move to the practical, I have created a module file dev.py and written a few lines of code-

language = 'Python'
framework = 'Django'

def hello_world():
    print('Hey !!! welcome back')

class ModuleTest:
    def get_language(self):
        print('My favorite language is - {}'.format(language))

In the below example I am accessing the above dev.py module by importing it in the current working directory path, as below -

>>> import dev
>>> dev.language

>>> dev.framework

>>> dev.hello_world()
Hey !!! welcome back

>>> obj = ModuleTest()
>>> obj.get_language()
My favorite language is - Python

How import works

As I told earlier when interpreter execute import dev statement, it searches sequentially in specific locations until it finds it -

01. It looks in the current directory where the input script was run.
02. PYTHONPATH - If PYTHONPATH is set, then Python will include the directories in sys.path for searching. You can set the: PYTHONPATH as below -

export PYTHONPATH='/some/extra/path'

and check like as below-

python -c "import sys; print(sys.path)"

o/p - ['', '/usr/lib/python36.zip',
'/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/home/prashant/.local/lib/python3.6/site-packages', '/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages']

03. An installation-dependent list of directories configured at the time Python is installed.

Additionally, we can put the module file in any of the directory and then modify sys.path at run-time so that it contains that directory. For example,
I can put my module dev.py in directory /home/prashant/Desktop and then update as following:

>>> sys.path.append('/home/prashant/Desktop')
>>> sys.path
['', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/home/prashant/.local/lib/python3.6/site-packages',
'/usr/lib/python3/dist-packages', '/home/prashant/Desktop']
>>> import dev
>>> dev.language

If a module is imported twice?

The module is only loaded the first time the import statement is executed and there is no performance loss by importing it again. You can examine sys.modules to find out which modules have already been loaded.

>>> import sys
>>> sys.modules.keys()
dict_keys(['builtins', 'sys', '_frozen_importlib', '_imp', '_warnings', '_thread', '_weakref', '_frozen_importlib_external', '_io', 'marshal', 'posix', 'zipimport', 'encodings', 'codecs', '_codecs', 'encodings.aliases', 'encodings.utf_8', '_signal', '__main__', 'encodings.latin_1', 'io', 'abc', '_weakrefset', 'site', 'os', 'errno', 'stat', '_stat', 'posixpath', 'genericpath', 'os.path', '_collections_abc', '_sitebuiltins', 'sysconfig', '_sysconfigdata_m_linux_x86_64-linux-gnu', '_bootlocale', '_locale', 'types', 'functools', '_functools', 'collections', 'operator', '_operator', 'keyword', 'heapq', '_heapq', 'itertools', 'reprlib', '_collections', 'weakref', 'collections.abc', 'importlib', 'importlib._bootstrap', 'importlib._bootstrap_external', 'warnings', 'importlib.util', 'importlib.abc', 'importlib.machinery', 'contextlib', 'backports', 'zope', 'sitecustomize', 'apport_python_hook', 'readline', 'atexit', 'rlcompleter', 'dev'])
>>> sys.modules['dev']
<module 'dev' from '/home/prashant/Desktop/dev.py'>

If intentionally you want it to be loaded/parsed again, you'd have to reload() the module.

For Python2.x

For above 2.x and <=Python3.3
import imp

For >=Python3.4
import importlib

Different forms of the import statement

1. import <module_name>

We can import the module using import statement and access the variables, methods, and classes inside it using the dot operator.

>>> import dev
>>> dev.language

2. from <module_name> import <name>

We can also import the specific variable, methods, classes from the module without importing it as a whole as below-

>>> from dev import language
>>> language

While we are using this form of import if any objects that already exists with the same name will be overwritten -

>>> language='java'
>>> from dev import language
>>> language

Because this form of import overwritten the object id into memory:
As you can differ in the below example -

>>> language='java'
>>> id(language)
>>> from dev import language
>>> id(language)

3. from <module_name> import <name> as <new_name>

We can also import a specific object from module with an alternative names, This can avoid conflict with previously existing names:

>>> language='java'
>>> from dev import language as lang
>>> lang

4. import <module_name> as <new_name>

We can also import the entire module with an alternate name:

>>> import dev as dev2
>>> dev2.language

5. from <module_name> import *

We can import everything from a module as following-

from dev import *

However, this is a highly discouraged practice. Since you are importing modules without control, some functions may get overwritten.

I hope that you now have a fair understanding of the How does the import module work in Python.

If you have any suggestions on your mind, please let me know in the comments.

Posted on by:


Editor guide

Great article however the order of import is swapped.
The "import " directive actually checks the sys.modules dictionary to see if the module has been imported before, if the module wasn't found, it will then start the search from the sys.path list of directories. Once found, it creates a module object from the "types.ModuleType" module and creates an entry in the sys.modules dictionary with the module name as the key and the module object as the value. It then compiles and executes the source of the module and creates a name entry in your globals() namespace.
Also, there is no difference between
from import name
Or import
If you check the sys.modules dict, you will always only find the name of the module. The only difference is in the globals() and the named reference to either the module.name or name only.


Thanks mate! Helped me a lot.