Reputation:
I'm trying to get all the functions that are defined in a given module (as opposed to imported by it), which I do like this:
from inspect import getmembers, isfunction
import my_module
fns = [fn for fn in vars(my_module).values() if isfunction(fn) and fn.__module__ == my_module.__name__]
The problem with the above is that if it's possible for my_module
to import a function from other_module
where other_module.__name__ == my_module.__name__
, then the above code will erroneously mark that function as defined in my_module
when it was actually defined in other_module
and imported by my_module
. I've been trying to create such a scenario but I can't seem to do that. I also know there's a sys.modules
which is a dictionary mapping strings to modules, which makes me think that maybe module names must be unique in the current scope. Is this possible?
Upvotes: 0
Views: 394
Reputation: 752
TL;DR of my finding is that module files may have a shared name, but the actually saved in the Python's sys.modules
is unique. Hence, it can be concluded that it is not possible for two or more modules to have the same name in Python.
To illustrate, we setup the following structures and explanation follows:
#add C:\superflous to the PYTHONPATH
C:\
superfluous\
mod.py
D:\
root\
mod.py
The question states:
if it's possible for my_module to import a function from
other_module
whereother_module.__name__ == my_module.__name__
For two modules to have the same __name__
, the module files name must be the same. But how to do it in Python context? We know we can't have two files with same name in a directory.
And, if we put in the ...sub\mod.py
the following line:
#...sub\mod.py
from mod import *
#or
import mod
...sub\mod.py
will just import itself and sys.modules
will include mod
as one of his dict
keys. We would like to import a module having the same as mod
, so let's import mod
from the C:superfluous\mod.py
. To do this we first put an __init__.py
inside sub
to turn it into a package directory and also to enable absolute import. In addition, let's add main.py
to the sub
directory. Our final structure:
D:\
root\
__init__.py
main.py
mod.py
We define main.py
and both of the mod.py
as follows:
#root\main.py
from . import mod
import sys
import types
print(f"{'mod:':<12}{{}}".format(sys.modules['mod']))
print(f"{'root.mod:':<12}{{}}".format(sys.modules['root.mod']))
print(f"{'-'*60}")
function_from_root_mod = (root_mod := sys.modules['root.mod'].__dict__).keys() - sys.modules['__main__'].__dict__
for i in function_from_root_mod:
if isinstance((root_mod_values := root_mod[i]), types.FunctionType) and root_mod_values.__module__ == 'root.mod':
print(f'func_name => {i} from modules "{root_mod_values.__module__}"')
#root\mod.py
from mod import *
def sub_mod_func(): pass
var_1 = 1
#C:\superfluous\mod.py
from collections import defaultdict
from itertools import permutations
def c_mod_func(): pass
We then execute main.py
through command prompt:
PS D:\> python -m root.main
the following is the output:
mod: <module 'mod' from 'C:\\superfluous\\mod.py'>
root.mod: <module 'root.mod' from 'D:\\root\\mod.py'>
------------------------------------------------------------
func_name => sub_mod_func from modules "root.mod"
Important findings:
.
) in main.py
translated into root.mod
and becomes a key as in sys.modules['root.mod']
mod.py
in C:\superfluous
becomes sys.modules['mod']
Module files may have the same name, but the paths (directory that containing them, e.g., D:\root\mod.py
) provide uniqueness for the sys.modules
keys.
Upvotes: 1