Reputation: 5784
I like clean APIs, thus I don't like having "internal" imports, like import numpy as np
inside of my modules, show up in the module API.
In my package (installable with setup.py) I have several sub-modules, of which each imports a set of modules, f.i. numpy
or builtins like sys
.
Let's say in my package mytools
I have a submodule mytools.mysubtools
in which I define a function foo
, which requires numpy
(imported with import numpy as np
). foo
is added to __all__ = ['foo']
.
Now I import this submodule with import mytools.mysubtools as mst
. When accessing mst
with code-completition (for example with Spyder IDE, PyCharm, Kite...) etc., it always shows all symbols and imports in mst
, in this case foo
and np
.
Can I avoid having imports like np
show up in the imported module, so that only foo
shows up?
Let's say my package structure looks like this:
/mytools/
|-- __init__.py # "mytools-init"
|-- my_subtools.py
|-- some_other_subtools.py
The __init__.py
file looks like this:
from . import my_subtools as mysubtools
__all__ = ['mysubtools']
And my_subtools.py
:
import numpy as np
__all__ = ['foo']
def foo():
return np.sqrt(4**3)
Now I import my_subtools
with
import mytools.mysubtools as mst
When using the imported module, code completition etc. always shows np
and foo
, f.i. when typing mst.
. For larger modules, with many imports and/or function/class definitions, this makes it really hard to use code completition, since a simple inspection of the API shows all imported modules and all definitions.
With __all__
it is possible to avoid importing all symbols for wild/star imports, like from mytools.mysubtools import *
. Can __all__
somehow also be used to mangle explicit imports?
Or is there any recommended way to avoid importing all symbols of a module?
For functions, I use name mangling, f.i. def _baz(): return 4**4
.
But is this also advisable for imports, f.i. import numpy as _np
? Any downsides?
What I'm looking for:
An explicit solution, since: Explicit is better than implicit.
For example something like __all__
, but for explicit imports. Or something like __except__ = ['np']
which excludes symbols from imports.
Upvotes: 0
Views: 569
Reputation: 5784
Thanks to the comments of @chepner, I've been looking into the linked implementation in the python standard library.
The conclusion is, that name mangling of imported modules is used frequently in the standard library. This is in my opinion a quite clear sign, that this is considered pythonic and/or has no severe downsides.
Several examples of name-mangling imports can be found, f.i.:
Which modules are name-mangled seems to change from file to file. It seems that the more "system-relevant" the module is, the less likely it is to be name mangled. For example imports like
import re as _re
import math as _math
are frequently name mangled, while import os as _os
is less commong. This is a merely my impression, so it may not be true in general.
Upvotes: 1
Reputation: 169308
__all__ = [...]
is a good hint of the "exportable" names, but it's just a hint. (Some IDEs such as PyCharm do tend to get the clue though.)
I definitely wouldn't do import numpy as _np
; you'd just be making your life harder.
You can't prevent someone from importing things from your module, if they're there... and if you really really wanted to, you of course could postfix all of your modules with mantras like del np, sys, os, quux, bar
; that way those names wouldn't be importable, but... I really don't think it's worth the effort.
Upvotes: 1