Lazy Imports

pcapkit.utilities.importlib holds lazy_exports(), which gives a package the PEP 562 __getattr__ and __dir__ that import each name it exports the first time the name is reached, rather than with the package itself. Every package under pcapkit.const imports its enumerations that way (#2729), so a caller pays only for the enumerations it uses. This module imports nothing from pcapkit; see Choosing Between utilities and corekit.

Added in version 1.6.0.

pcapkit.utilities.importlib.lazy_exports(package, namespace, exports=None, *, packages=())[source]

Return the __getattr__ and __dir__ of a package that imports its exports on first use.

A package binds both at module level, after its __all__, and imports the exported names only under TYPE_CHECKING, for the type checkers:

if TYPE_CHECKING:
    from pcapkit.const.tcp.option import Option as TCP_Option

__all__ = ['TCP_Option']

__getattr__, __dir__ = lazy_exports(__name__, globals(), {
    'TCP_Option': ('option', 'Option'),
})

PEP 562 calls __getattr__ only for a name missing from the package’s globals. For an exported name it imports the submodule, reads the attribute off it and binds it in namespace, so it runs once per name; for the name of a submodule an export comes from, it imports that submodule, which the import system binds on the package. So from package import Name, import package.submodule, attribute access, import * and the pickle of an object defined in a submodule all behave as an eager import would, apart from when the import happens.

__dir__ lists what the eager import would have bound: the names the import system sets, __all__, every export, every submodule an export comes from, and any other submodule already imported. The package’s own helpers – TYPE_CHECKING, this function, the two hooks – are left out.

Parameters:
  • package (str) – The package’s __name__.

  • namespace (dict[str, Any]) – The package’s globals(), which __getattr__ binds each name in once it is imported.

  • exports (Mapping[str, tuple[str, str]] | None) – The names imported on first use, each mapped to the submodule it is defined in, relative to package, and its name there.

  • packages (Iterable[str]) – Subpackages, relative to package, whose __all__ this package re-exports. Each is imported by this call – one using lazy_exports() itself imports none of its exports – and every name in its __all__ is read off it on first use.

Return type:

tuple[Callable[[str], Any], Callable[[], list[str]]]

Returns:

The package’s __getattr__ and __dir__.