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: 0x20456766590
Code 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 ceil
Code language: JavaScript (javascript)
is more efficient than:
import math
Code 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 thesys.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.