3

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.

3
  • Why do you want to do this? Commented Jun 2, 2021 at 20:55
  • This type of design is almost always advised against, but you could theoretically create closure functions/function factories that generate the module's functions (or eval if you really know what you're doing) - though I can't think of a situation where this would be the best approach. Commented Jun 2, 2021 at 21:00
  • I promise I have very good reasons, and they're all secret. Commented Jun 2, 2021 at 21:07

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.