Suppose I have the dict of a module (via vars(mod)
, or mod.__dict__
, or globals()
), e.g.:
import mod
d = vars(mod)
Given the dict d
, how can I get back the module mod
? I.e. I want to write a function get_mod_from_dict(d)
, which returns the module if the dict belongs to a module, or None
:
>>> get_mod_from_dict(d)
<module 'mod'>
If get_mod_from_dict
returns a module, I must have that this holds:
mod = get_mod_from_dict(d)
assert mod is None or mod.__dict__ is d
I actually can implement it like this:
def get_mod_from_dict(d):
mods = {id(mod.__dict__): mod for (modname, mod) in sys.modules.items()
if mod and modname != "__main__"}
return mods.get(id(d), None)
However, this seems inefficient to me, to iterate through sys.modules
.
Is there a better way?
Why do I need this?
In some cases, you get access to the dict only. E.g. in the stack frames. And then, depending on what you want to do, maybe just for inspection/debugging purpose, it is helpful to get back the module.
I wrote some extension to Pickler
which can pickle methods, functions, etc. Some of these have references to the module, or the module dict. Wherever I have a dict which belongs to a module during pickling, I don't want to pickle the dict, but instead a reference to the module.
Every module has a __name__
attribute that uniquely identifies the module in the import system:
>>> import os
>>> os.__name__
'os'
>>> vars(os)['__name__']
'os'
Imported modules are also cached in sys.modules
, which is a dict mapping module names to module instances. You can simply look up the module's name there:
import sys
def get_mod_from_dict(module_dict):
module_name = module_dict['__name__']
return sys.modules.get(module_name)
Some people have expressed concern that this might not work for (sub-)modules in packages, but it does:
>>> import urllib.request
>>> get_mod_from_dict(vars(urllib.request))
<module 'urllib.request' from '/usr/lib/python3.7/urllib/request.py'>
There is a very minor caveat, though: This will only work for modules that have been properly imported and cached by the import machinery. If a module has been imported with tricks like How to import a module given the full path?, it might not be cached in sys.modules
and your function might then unexpectedly return None
.
You can use importlib.import_module to import a module given it's name. Example for numpy
In [77]: import numpy
...: import importlib
In [78]: d = vars(numpy)
In [79]: np = importlib.import_module(d['__name__'])
In [80]: np.array([1,2,3])
Out[80]: array([1, 2, 3])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With