We are the Mods: Modules & Package (and Scripts)#
Basic Module and Package Layout#
A typical Python code layout structures the code in package directories and module files.
A very simple package structure could look like this:
Suppose these files have the following contents:
This package can now be used as follows:
>>> import mypackage
mypackage
>>> mypackage.module1.f() # this will fail: mypackage.module1 not yet imported
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'mypackage' has no attribute 'module1'
>>>
>>> import mypackage.module1
I'm module 1
>>> mypackage.module1.f()
Module 1 is great
>>> import mypackage.module2
I'm module 2
>>> mypackage.module2.f()
Module 2 is also great
>>>
>> import mypackage.module1 # 2nd import
>>>
Some things to note:
- code in an
__init__.py
-file in a package dir gets executed when the package is imported __init__.py
code is just regular Python code- statements in a module get executed when the module is imported
- modules are imported only once per interpreter session (you can enforce reload in interactive sessions)
Regular and Namespace Packages#
Module Search Path#
Lookup of modules involves a search path. The search order for mod.py
is
- look for a built-in module with that name
- look in the directories available in
sys.path
for themod.py
file
sys.path
basically contains
- the directory containing the importing file, or the current working directory if no file, i.e. in an interactive interpreter session
- the directories set in the (optional)
PYTHONPATH
environment variable -
the default directories of the Python installation, e.g. for a Python 3.6 linux installation:
Scripts#
Scripts are Python modules that are intended to be run as executables. More often that not such scripts will want to parse command line options, receive stdin input or user input and write stdout output or output file(s).
Often, the duality of a script also being a normal module makes it desirable to have it act both as an importable module as well as an executable.
In such situations it makes sense to guard the executable operations with:
if __name__ == "__main__":
# everything here will only get executed when run as the main module
# i.e. the special name __name__ contains the string "__main__"
...
The special name __name__
is set to "__main__"
for the main file that
gets executed by the Python interpreter, e.g.
or
if this file has been made executable.
Note: The main file run by the Python interpreter doesn't need to have
the .py
file extension, so you can make such a file look like an executable
or command with regard to its file name ("myprogram"). However, it is not
importable itself, then.
Here's a template for a basic command line script:
import sys
def parse_args(args=None):
"""Parse arguments from sys.argv if args is None (the default) or from args
sequence otherwise.
"""
import argparse
parser = argparse.ArgumentParser()
# Add arguments here
args = parser.parse_args(args)
return args
def main(args=None):
"""Main module function.
Exposes this modules' executable functionality for use as a module
function.
Parses arguments from sys.argv if args is None (the default) or from args
sequence otherwise.
"""
args = parse_args(args)
# Add main code here
if __name__ == "__main__":
sys.exit(main())
Hint: More elaborate Python libraries that contain many packages and
modules may want use the
console_scripts
entry point functionality of setuptools
.
This is allows you to expose functions of your library (the "entry points")
as command line scripts, automatically generated by setuptools
when building
the installable library package from the source code files.
You can find more information on this here or in the Python Packaging User Guide.