user108471
user108471

Reputation: 2607

How do I dynamically generate module contents in Python?

I know there are ways to perform dynamic import of Python modules themselves, but I would like to know if there's a way to write a module such that it can dynamically create its own module contents on demand. I am imagining a module hook that looks something like:

# In some_module.py:
def __import_name__(name):
    return some_object

Such that if I were to write from some_module import foo in a script, Python will call some_module.__import_name__("foo") and let me dynamically create and return the contents.

I haven't found anything that works like this exactly in the documentation, though there are references to an "import protocol" with "finders" and "loaders" and "meta hooks" and "import path hooks" that permit customization of the import logic, and I imagine that such a thing is possible.

Upvotes: 3

Views: 1087

Answers (1)

user108471
user108471

Reputation: 2607

I discovered you can modify the behavior of a Module from within itself in arbitrary ways by setting sys.modules[__name__].__class__ to a class that implements whatever your chosen behavior.

import sys
import types

class DynamicModule(types.ModuleType):
    # This function is what gets called on `from this_module import whatever`
    # or `this_module.whatever` accesses.
    def __getattr__(self, name):
        # This check ensures we don't intercept special values like __path__
        # if they're not set elsewhere.
        if name.startswith("__") and name.endswith("__"):
            return self.__getattribute__(name)
        return make_object(name)

    # Helpful to define this here if you need to dynamically construct the
    # full set of available attributes.
    @property
    def __all__(self):
        return get_all_objects()

# This ensures the DynamicModule class is used to define the behavior of
# this module.
sys.modules[__name__].__class__ = DynamicModule

Something about this feels like it may not be the intended path to do something like this, though, and that I should be hooking into the importlib machinery.

Upvotes: 1

Related Questions