Search notes:

Python: import statement

The import statement searches the directories in sys.path for modules and packages.

The basic import statement

The following text is the content of a (simple Python script) file named TQ84_Module.py. The script defines one function: func().
def func():
    print('func within TQ84_Module')
Github repository about-python, path: /statements/import/import-module/TQ84_Module.py
This file can be imported with an import statement so that its functionality (here func()) is available to other modules and scripts.
In order to import a script file, its name, without .py extension, needs to be given after the import statement (here import TQ84_Module).
In order to use the function, the function's name needs to be prepended with the module name where it is located (here: TQ84_Module.func()):
#!/usr/bin/python

import TQ84_Module

#
#  The identifiers that are defined in the imported
#  module can be accessed by prepending them with the
#  module name.
#
TQ84_Module.func()
Github repository about-python, path: /statements/import/import-module/go.py

from MODULE import *

Here's another module (FooModule.py) to be imported. Again, it defines one function: doFoo():
def doFoo():
    print('doFoo() in FooModule')
Github repository about-python, path: /statements/import/from-module-import-star/FooModule.py
The following script does a from FooModule import * (as opposed to the previous import FooModule construct).
With this special construct, the identifiers that are defined in FooModule will be placed into the global namespace so that they don't need to be prefixed with the module name in order to be accessed, so doFoo() can be called without prefixing it with a module name:
#!/usr/bin/python

from FooModule import *

#
# When the module is imported with the
#   from MODULE import *
# construct, the module's identifiers don't
# need to be prepended with the module name:
#
doFoo()
Github repository about-python, path: /statements/import/from-module-import-star/go.py

import executes the imported module

The following example demonstrates that the import statement not only puts a new name into the current namespace, but also executes the module that is imported.
This is the module that is imported. Note, the call of the print function is not within a function that is defined in the module.
print('This is printed from within tq84Module')
Github repository about-python, path: /statements/import/run-imported-module/tq84Module.py
When a script uses import tq84Module, the content of tq84Module.py is executed. So, running the following code will print This is printed from within tq84Module.
#!/usr/bin/python

import tq84Module
Github repository about-python, path: /statements/import/run-imported-module/importer.py

Packages (modules stored in directories and subdirectories)

Modules that semantically belong together can be stored in their own directory (or sub directories). This helps to recognize their relationship and reduces namespace cluttering when importing them.
This is demonstrated with the following two files, mod_one.py and mod_two.py, where are both stored in a directory tq84_dir.

Imported files

tq84_dir/mod_one.py:
def func():
    print('I was defined in mod_one')
tq84_dir/mod_two.py:
def func():
    print('I was defined in mod_two')

Importing these files

Before doing anything, I store the names of the current local scope in the variable global_names so that I can compare it with the names in the current local scope after executing the import stateemnt:
>>> global_names = dir()
>>> print(global_names)
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
I now execute the an import statement. In contrast to the previous examples, this time, the name tq84_dir refers to a file system directory rather than a file name:
import tq84_dir
I perform a diff between the names that are stored in global_names and those that are now present in the current local scope and store the result in new_names:
>>> new_names = list(set(dir()) - set(global_names))
>>> print(new_names)
['tq84_dir', 'global_names']
It turns out that importing the tq84_dir module (package) has created a corresponding new name (tq84_dir) in the current local scope.
(global_names was created after the first call of dir() executed, hence it is also reported)
The type of tq84_dir is module:
>>> print(type('tq84_dir'))
<class 'module'>
As before, I store the list of attributes that are present in the tq84_dir module in a variable to be able to diff it later.
>>> tq84_names_init = dir(tq84_dir)
Although the directory contains two files (sub modules?), they are not yet loaded (imported):
>>> print(tq84_names_init)
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__']
It's about time to import mod_one.py and check how it influences the namespace of tq84_dir:
>>> import tq84_dir.mod_one
>>> tq84_names_1 = dir(tq84_dir)
>>> new_names = list(set(tq84_names_1) - set(tq84_names_init))
>>> print(new_names)(
['mod_one']
Same thing with mod_two.py:
>>> import tq84_dir.mod_two
>>> tq84_names_2 = dir(tq84_dir)
>>> new_names = list(set(tq84_names_2) - set(tq84_names_1))
>>> print(new_names)
['mod_two']
Finally, I call the functions that were defined in these package-modules:
>>> tq84_dir.mod_one.func()
I was defined in mod_one
>>> tq84_dir.mod_two.func()
I was defined in mod_two
These statements are also recorded here.

import executes an imported package's __init__.py

The following example demonstrates the automatic execution of an __init__.py file (if it is present).
Here's the __init__.py file: it is stored under tq84Package:
print('This is printed from within tq84Package/__init__.py')
Github repository about-python, path: /statements/import/run-__init__/tq84Package/__init__.py
Here's a script that imports tq84Package:
import tq84Package
Github repository about-python, path: /statements/import/run-__init__/import-package.py
While the import statement is executed, the following message is printed:
This is printed from within tq84Package/__init__.py
The directory tq84Package also contains the file tq84Module.py:
print('This is printed from within tq84Package/tq84Module.py')
Github repository about-python, path: /statements/import/run-__init__/tq84Package/tq84Module.py
This tq84Module is imported like so:
import tq84Package.tq84Module
Github repository about-python, path: /statements/import/run-__init__/import-module.py
This will print:
This is printed from within tq84Package/__init__.py
This is printed from within tq84Package/tq84Module.py
Compare with the __main__.py that might be executed as part of -m command line option.

Dunders of an empty module

The following script imports a file (Empty.py) that is literally empty (its size is 0 bytes) and then uses dir(Empty) to show the module's attributes (all of which are so called dunders).
It then goes on to also print the values of the interesting, imho, attributes __name__, __package__, __file__ and __doc__:
import Empty

print(dir(Empty))
#
#  ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']


print(Empty.__name__)
#
#  Empty

print(Empty.__package__)
#
#

print(Empty.__file__)
#
#  C:\Users\rene\about\Python\statements\import\Empty.py


print(Empty.__doc__)
#
#  None
Github repository about-Python, path: /statements/import/import-Empty.py

See also

importlib
statements
import this prints the Zen of Python. Not sure if this is a module, though.
The -v command line option traces import statements.

Index