Understanding How Python import Statement Works Under the Hood (original) (raw)

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:

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:

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:

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:

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': , 'acosh': , 'asin': ,

.... 'tau': 6.283185307179586, '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 #

Was this tutorial helpful ?