Python import

Summary: in this tutorial, you will examine the Python import statement variants and how they work under the hood.

import module

When you import a module, Python does two things:

  • First, check if the module has been loaded and cached in the sys.modules. If not, it will execute the module and create a reference to the module object.
  • Second, add the module name to the global namespace referencing the same module object.

The following program imports the math module and prints out the math object in the sys.modules and global namespace:

import sys
import math


print('sys.modules:', hex(id(sys.modules['math'])))

if 'math' in globals():
    print('globals: ', hex(id(globals()['math'])))Code language: JavaScript (javascript)

Output:

sys.modules: 0x20456766590
globals:  0x20456766590Code language: HTTP (http)

As you can see, the math variable references the same module object.

If you import a module for the second time, Python does not execute the math module again but gets it from the sys.modules cache.

from module import object

When you import an object (a function, a class, etc., ) from a module, Python does the following:

  • First, check if the module has been loaded and cached in the sys.modules. If not, it will execute the module and create a reference to the module object.
  • Second, add the import object to the global namespace.

In this case, Python does not add a variable that references the module to the global namespace but a variable that references the imported object.

The following example imports the ceil function from the math object:

import sys
from pprint import pprint
from math import ceil

print('sys.modules:', hex(id(sys.modules['math'])))

pprint(globals())
Code language: JavaScript (javascript)

Output:

sys.modules: 0x11d659c2130
{'__annotations__': {},
 '__builtins__': <module 'builtins' (built-in)>,
 '__cached__': None,
 '__doc__': None,
 '__file__': 'C:/oop/app.py',
 '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000011D65A008E0>,
 '__name__': '__main__',
 '__package__': None,
 '__spec__': None,
 'ceil': <built-in function ceil>,
 'pprint': <function pprint at 0x0000011D661C4040>,
 'sys': <module 'sys' (built-in)>}Code language: PHP (php)

In this example, Python loads the math module into the sys.modules. However, it only creates a reference to the ceil function, not the math module object in the global namespace.

from module import object as object_alias

When you load an object from a module and use an alias, Python will do the following:

  • First, check if the module has been loaded and cached in the sys.modules. If not, it will execute the module and create a reference to the module object.
  • Second, create an alias that references the imported object and add it to the global namespace.

For example, the following imports the ceil function from the math module and use the ceiling alias:

import sys
from math import ceil as ceiling

print('sys.modules:', hex(id(sys.modules['math'])))
print('globals:', hex(id(globals()['ceiling'])))Code language: JavaScript (javascript)

Output:

sys.modules: 0x1cc4f244ae0
{'__annotations__': {},
 '__builtins__': <module 'builtins' (built-in)>,
 '__cached__': None,
 '__doc__': None,
 '__file__': 'C:/oop/app.py',
 '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001CC4EA708E0>,
 '__name__': '__main__',
 '__package__': None,
 '__spec__': None,
 'ceiling': <built-in function ceil>,
 'pprint': <function pprint at 0x000001CC4F234040>,
 'sys': <module 'sys' (built-in)>}Code language: PHP (php)

from module import *

When you import everything from a module, Python will do the following:

  • First, check if the module has been loaded and cached in the sys.modules. If not, it will execute the module and create a reference to the module object.
  • Second, add all symbols from the module to the global namespace.

For example, the following imports all the objects from the math module:

import sys
from pprint import pprint
from math import *

print('sys.modules:', hex(id(sys.modules['math'])))
pprint(globals())Code language: JavaScript (javascript)

Output:

sys.modules: 0x1e1ebf24b30
{'__annotations__': {},
 '__builtins__': <module 'builtins' (built-in)>,
 '__cached__': None,
 '__doc__': None,
 '__file__': 'C:/oop/app.py',
 '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001E1EB7408E0>,
 '__name__': '__main__',
 '__package__': None,
 '__spec__': None,
 'acos': <built-in function acos>,
 'acosh': <built-in function acosh>,
 'asin': <built-in function asin>,

 ....
 'tau': 6.283185307179586,
 'trunc': <built-in function trunc>}Code language: PHP (php)

As you can see clearly from the output, Python adds all the functions from the math module to global namespaces. In this case, if any symbols exist in the global namespace, Python will replace their references.

This often leads to bugs that are difficult to track. Therefore, you should avoid using the from module import *

Python import misconception

One of the most common misconceptions of the import statement is that many consider the following statement:

from math import ceilCode language: JavaScript (javascript)

is more efficient than:

import mathCode language: JavaScript (javascript)

Because the first statement imports only the ceil function while the second statement imports the whole math module.

However, Python loads the whole math module in both cases.

The first statement creates a symbol that references the ceil function from the math module while the second statement creates the math symbol that references the math module object.

Summary

  • The Python import statement only loads a module once and caches it in the sys.modules.
  • Avoid using the from module import * because it may cause a bug.
  • Do not use from module import object to optimize the program speed because it won’t.
Did you find this tutorial helpful ?