Repeated import path patterns in python
There is no miracle cure for this problem.
There are, however, a few strategies you can use to make your imports a little bit nicer:
Import all names from a module at the same time
Instead of
from a.b.c.d.e.f.g import g1 from a.b.c.d.e.f.g import g2
use
from a.b.c.d.e.f.g import g1, g2
Use relative imports (if you're importing within your own package)
Assuming that this import is happening in
a.b.c.d.e
, you can replacefrom a.b.c.d.e.f.g.h import h1
with
from .f.g.h import h1
This also works if you're in a sibling (sub-)module. For example, if this import is taking place in
a.b.c.d.e.x.y
, you can usefrom ...f.g.h import h1
For more details about relative imports, see
- Intra-package references
- How to do relative imports in Python?
- Relative imports for the billionth time
Refactor your package (if it's your own code)
If your package has more than 4 levels of submodules (like
a.b.c.d.e
), there's a pretty high chance that you should rethink your package structure. At that point you're really just shooting yourself in the foot. Perhapsc
could be a standalone package, outside ofa
. Or perhapse
doesn't really need to be insided
and can be moved up a level or two. To quote the Zen of Python: Flat is better than nested.
Critique of other suggestions
importlib.import_module
Someone suggested this:
import importlib ref_path = 'a.b.c.d.e.f.g' g1 = importlib.import_module(ref_path).g1 h1 = importlib.import_module(ref_path).h.h1
This serves absolutely no purpose. Now you have to write
importlib.import_module(ref_path)
instead offrom a.b.c.d.e.f import
. It's not shorter. It's not more readable. It's nothing but a more verbose version of the next suggestion. (Read on...)Assigning
a.b.c.d.e.f
to a variableThe next suggestion was this:
import a.b.c.d.e.f.g as ref g1 = ref.g1 h1 = ref.h.h1
This looks nice, but it doesn't always work. If the
g
module doesn't automatically import theh
submodule, this code will throw an AttributeError. To demonstrate:>>> import urllib as ref >>> urlopen = ref.request.urlopen Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: module 'urllib' has no attribute 'request' >>> >>> from urllib.request import urlopen # this works, though >>>
If this is inside your own package, there's an additional disadvantage to this solution: Your IDE most likely won't understand your imports, and won't automatically update them for you if you ever refactor your package structure. In the long run, old-fashioned
import
statements are more maintainable.
You can try to use importlib
as follows:
import importlib
ref_path = 'a.b.c.d.e.f.g'
g1 = importlib.import_module(ref_path).g1
h1 = importlib.import_module(ref_path).h.h1
Edit: Another way of doing it could be to import the ref path as a package and then assigning the sub-modules to local variables as follows:
import a.b.c.d.e.f as ref
g1 = ref.g1
h1 = ref.h.h1