In this lesson, you’ll learn about subpackages. Packages can contain nested subpackages to arbitrary depth. For starters, let’s make one more modification to the example package directory as follows:

The four modules (mod1.py
, mod2.py
, mod3.py
, and mod4.py
) are defined as they were before. But now, instead of being lumped together into the pkg
directory, they are split out into two subpackage directories: sub_pkg1
and sub_pkg2
.
Importing still works the same as you saw before. Syntax is similar, but additional dot notation is used to separate the package name from the subpackage name:
>>> import pkg.sub_pkg1.mod1
>>> pkg.sub_pkg1.mod1.load_data()
loading data using mod1.load_data()
>>> from pkg.sub_pkg1 import mod2
>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__',
'__spec__', 'help', 'mod2', 'pkg']
>>> mod2.clean_data()
cleaning data using mod2.clean_data()
>>> from pkg.sub_pkg2.mod3 import merge_data
>>> merge_data()
merging data using mod3.merge_data()
>>> from pkg.sub_pkg2.mod4 import Winner as Result
>>> x = Result()
>>> x
<pkg.sub_pkg2.mod4.Winner object at 0x108159588>
In addition, a module in one subpackage can reference objects in a sibling subpackage (in the event that the sibling contains some functionality that you need). For example, suppose you want to import and execute load_data()
(defined in module mod1
) from within module mod3
. You can use an absolute import:
def merge_data():
print('merging data using mod3.merge_data()')
class Message:
pass
from pkg.sub_pkg1.mod1 import load_data
load_data()
Here’s what that looks like:
>>> from pkg.sub_pkg2 import mod3
loading data using mod1.load_data()
>>> mod3.load_data()
loading data using mod1.load_data()
Or you can use a relative import, where ..
refers to the package one level up. From within mod3.py
, which is in subpackage sub_pkg2
:
..
evaluates to the parent package (pkg
)..sub_pkg1
evaluates to subpackagesub_pkg1
of the parent package.
Here’s pkg/sub__pkg2/mod3.py
:
def merge_data():
print('merging data using mod3.merge_data()')
class Message:
pass
from .. import sub_pkg1
print(sub_pkg1)
from ..sub_pkg1.mod1 import load_data
load_data()
Here’s what you get:
>>> from pkg.sub_pkg2 import mod3
<module 'pkg.sub_pkg1' (namespace)>
loading data using mod1.load_data()
>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__',
'__spec__', 'help', 'mod3']
danny vw on March 4, 2020
Short question: if we have an additional level, e.g., grandparent_pkg/pkg1/sub_pkg2/mod3.py and suppose I need to go via the grandparent to reach some other modules in grandparent_pkg/pkg2/sub_pkg7/mod8.py. To go up to the grandparent from within mod3.py do we use then something like ../..pkg2.sub_pkg7/mod8.py ?