Packages

Packages

When regular ol’ modules aren’t cutting it, you want to turn to packages. They allow you to, among other things:

  • Better organize your code with explicit names
    • e.g. from email.message import Message
  • Only import what you need

__init__ files

These files, tucked into subdirectories, establish a subdirectory as a namespace under the umbrella that is the package.

Consider a path that looks like this

!tree /f /a
Folder PATH listing for volume OSDisk
Volume serial number is 16C3-CD43
C:.
|   Caching Imports.ipynb
|   localscript.py
|   Modules.ipynb
|   Packages.ipynb
|   Pathing.ipynb
|   
\---samplepackage
    |   nested.py
    |   __init__.py
    |   
    \---subdirectory
            doublenested.py
            __init__.py

Executing code in __init__ files

__init__ files can be used to execute at the time of import, but only once.

For example, our __init__ files call print statements like so:

!type "samplepackage\__init__.py"
import os

print("Automatically printing import statement from file located at:", '\n',
      __file__)
!type "samplepackage\subdirectory\__init__.py"
import os

print("Automatically printing import statement from file located at:", '\n',
      __file__)

Thus, importing the nested.py file one level below yields

import samplepackage.nested
Automatically printing import statement from file located at: 
 C:\Users\nhounshell\Documents\github\BlackBook\Python\Modules and Packages\samplepackage\__init__.py

Similarly, importing the doublenested.py file two levels down gives a print statement, but only from the second level.

from samplepackage.subdirectory import doublenested
Automatically printing import statement from file located at: 
 C:\Users\nhounshell\Documents\github\BlackBook\Python\Modules and Packages\samplepackage\subdirectory\__init__.py

However, if you want to get both print statements, for whatever reason, all you have to do is delete the namespace refrerence in the sys.modules dictionary.

import sys

del sys.modules['samplepackage']
del sys.modules['samplepackage.subdirectory']
from samplepackage.subdirectory import doublenested
Automatically printing import statement from file located at: 
 C:\Users\nhounshell\Documents\github\BlackBook\Python\Modules and Packages\samplepackage\__init__.py
Automatically printing import statement from file located at: 
 C:\Users\nhounshell\Documents\github\BlackBook\Python\Modules and Packages\samplepackage\subdirectory\__init__.py
import sys

del sys.modules['samplepackage']
del sys.modules['samplepackage.subdirectory']
del sys.modules['samplepackage.nested']
del sys.modules['samplepackage.subdirectory.doublenested']

Updating our namespace records

To start off, there isn’t anything in our sys.modules dictionary yet.

[x for x in sys.modules if x.startswith('samplepackage')]
[]

But if we use the ‘from __ import __’ syntax and go two levels deep

from samplepackage.subdirectory import doublenested
Automatically printing import statement from file located at: 
 C:\Users\nhounshell\Documents\github\BlackBook\Python\Modules and Packages\samplepackage\__init__.py
Automatically printing import statement from file located at: 
 C:\Users\nhounshell\Documents\github\BlackBook\Python\Modules and Packages\samplepackage\subdirectory\__init__.py

We’ll see that the __init__ files have created sys.modules entries every step of the way.

[x for x in sys.modules if x.startswith('samplepackage')]
['samplepackage',
 'samplepackage.subdirectory',
 'samplepackage.subdirectory.doublenested']