Python modules

From wikinotes

Sample Project

myproject/
|   utils/
|   |-  __init__.py
|   |-  filesystem.py
|   +-  platform.py
|
|-  __init__.py
+-  core.py

Concepts

terminology

Python code is organized into packages and modules.

  • a package is a directory containing the file __init__.py, and optionally other modules.
  • a module is a python file yourfile.py

$PYTHONPATH

Importing a package/module means adding all of the variables/functions/classes from that file into the current file.

A module or package can be imported once it is added to the environment variable $PYTHONPATH. The $PYTHONPATH is similar to the $PATH variable, it can contain multiple directories separated by a ':' (unix) ';' (windows).

If you have a package nested within another package, only the top-most package needs to be added to the path.

site-packages

This is the location that external python-packages get installed to. You can customize, alter, or add to your list of site-packages directories. See https://docs.python.org/3/library/site.html

importing code

import

When importing a package, it's __init__.py is treated as that package's module. Any functions, clases etc defined there will imported with the package.

import module                 # $PYTHONPATH/module.py
import package.module         # $PYTHONPATH/package/module.py
import package.subpkg.module  # $PYTHONPATH/package/subpkg/module.py

Once a module is imported, it can be used using the full importpath

package.subpkg.module.my_func()

This is a lot of typing. Alternatively, you can use the keywords from or as to change what your module is referred to as.

# $PYTHONPATH/package/subpkg/module.py
from   package import subpkg            # subpkg.function()
from   package.subpkg import module     # module.function()

import package.subpkg.module as module  # module.function()

NOTE:

you can import specific classes/functions from a module, but it is considered a bad practice.

It makes it difficult to discern where each item came from, makes it easier to accidentally create a name-clash, makes it more complicatedto reload a module.

NOTE:

you can import modules/packages from anywhere within your module. If you import a module within a function, you add it to only that function's namespace.

Not adding modules at the top of your file is considered a bad practice. It makes it more difficult to do refactoring, it is difficult to predict dependency-cycles, and it means more duplicate code.

importlib

You can also dynamically import items:

import importlib
module = importlib.import_module( my.package.module )

magic modules

__init__.py Marks the parent directory as a python-package. This files contents will be available from the imported package's namespace.
__main__.py If a python package (or a package.zip) is run directly, this file's contents are run. Ex: python mypackage.zip.

Lazy Module Attributes

See https://docs.python.org/3.6/reference/datamodel.html#customizing-module-attribute-access And https://stackoverflow.com/questions/1462986/lazy-module-variables-can-it-be-done

import sys
import types

class _Sneaky(types.ModuleType):
    @property
    def DOWNLOAD_FOLDER_PATH(self):
        if not hasattr(self, '_download_folder_path'):
            self._download_folder_path = '/dev/block/'
        return self._download_folder_path
sys.modules[__name__].__class__ = _Sneaky