Imagine I have a module with two files, like this:
mymodule
|-- __init__.py
`-- submodule.py
mymodule/__init__.py
contains:
SOME_CONSTANT_ONE = 1
SOME_CONSTANT_TWO = 2
SOME_CONSTANT_THREE = 3
...
SOME_CONSTANT_ONE_HUNDRED = 100
def initialize():
pass # do some stuff
def support_function():
pass # something that lots of other functions might need
I already know that I can use a relative import to bring in specific objects from the __init__.py
file, like this:
submodule.py:
from . import initialize, support_function
def do_work():
initialize() # initialize the module
print(support_function()) # do something with the support function
But now what I want to know is if I can import all of the constants from the __init__.py
file, but simultaneously have them appear in a namespace.
What won't work (what I've tried/considered):
import mymodule as outer_module
works, since the import system already has knowledge of where the module is. However, if I ever need to change the name of the outer module, that code will break.import . as outer_module
doesn't work.from . import *
does work but puts all of the objects in __init__.py
in the current namespace rather than in the sub-namespace.from . import SOME_CONSTANT_ONE as outer_constant_1, SOME_CONSTANT_TWO as outer_constant_2, SOME_CONSTANT_THREE as outer_constant_3, ...
is ugly and won't bring in any new constants should they be defined later on in __init__.py
.What I really want is something like this:
submodule.py:
SOME_CONSTANT_ONE = "one!" # We don't want to clobber this.
import . as outer_module # this does not work, but it illustrates what is desired.
def do_work():
print(SOME_CONSTANT_ONE) # should print "one!"
print(outer_module.SOME_CONSTANT_ONE) # should print "1"
I know that I could move all of the constants to a constants.py
file and then I should be able to import it with from . import constants (as something)
but I'm working on existing code and making that change would require a lot of refactoring. While that's not a bad idea, I'm wondering, given that Python does have a way to import individual objects, and also to import the whole module by name to an explicit name, if I can maybe do something with importlib
to accomplish importing everything from __init__.py
into a namespace?
The loader sets __package__
which you can use:
import sys
SOME_CONSTANT_ONE = "one!" # We don't want to clobber this.
outer_module = sys.modules[__package__]
def do_work():
print(SOME_CONSTANT_ONE) # should print "one!"
print(outer_module.SOME_CONSTANT_ONE) # should print "1"
This is precisely the attribute from which relative imports are based. See PEP 366 for details.
However, I really think the backwards-compatible refactoring which the other answer suggests is probably the better approach here.