Tricks with `sys.modules`?

Its documentation says:

This is a dictionary that maps module names to modules which have already been loaded. This can be manipulated to force reloading of modules and other tricks.

What kind of tricks? One I’ve seen here is that sys.modules['_decimal'] = None before importing the decimal module apparently prevents importing the C version of the module so that the Python version gets used. And I just used this trick to get the Python version of bisect.

Is that documented somewhere? And what other tricks can we do with it?

The most common trick I’ve seen is modules replacing themselves in sys.modules with a class instance. For example, the third-party sh package does this with the SelfWrapper class to extend the module type, so that from-imports can lean on __getattr__ magic.

I don’t think it’s separately documented - it’s a natural consequence of the bit of documentation you cite, in combination with how decimal, bisect etc. implement wrapping the C libraries.

Unless you specifically mean how importing treats None entries in sys.modules:

>>> import sys
>>> sys.modules['this'] = None
>>> import this
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: import of this halted; None in sys.modules

In that case, the relevant documentation is here.

Following the diataxis model, perhaps we could have guides etc. that explicitly exploit this technique.

1 Like

Excellent, thanks. Yes, I specifically meant the None thing. Nice to see it’s not just a hack the SO commenter made up and that happens to work, but that that’s documented.