I have a small package that has a few dependencies such as pandas and gensim. The file structure is like so
/package
__init__.py
agg_clean.py
In the __init__.py
file, I have import agg_clean
so I am able to access the functions in a chained manner, e.g.:
import package as pkg
pkg.agg_clean.function()
However, I have a couple of import statements in agg_clean.py
, (pandas, os, etc.). when I do a chained import as above, I am also able to access the imports in agg_clean
, e.g. pkg.agg_clean.os.listdir()
How can I hide imports from my various modules in the package import?
tl;dr: You can't cleanly. Or more accurately, you shouldn't be worried about things like this.
There's no namespace collisions
in this case, since the os module is loaded under then name pkg.agg_clean.os
. If the user wants to use your imported os package, there is no harm in letting them do that. On top of that, there's no good way to prevent them from doing that.
There's something interesting to remember here. Take the following python module that can be imported by another python script:
# module_im_importing.py
import os as _os
__all__ = ["echo"]
name_not_available = 'some_constant_string'
def echo(object):
pass
If your user imports the bare module using import module_im_importing
, all defined variables are made available to their environment under the name module_im_importing
.
>>> import module_im_importing
>>> dir() # Lookup local namespace
['__builtins__', '__doc__', '__name__', '__package__', 'module_im_importing']
>>> dir(module_im_importing) # See defined items in your package.
['__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', 'echo', 'name_not_available', 'os']
If they instead from module_im_importing import *
(which is discouraged), the behavior is a little different:
>>> from module_im_importing import *
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'echo']
This causes the names defined in the file module_im_importing.py
to be imported into the user's local namespace. Because we used __all__
in your module, only the items defined in __all__
are imported to the users local namespace from your module. This can pollute their namespace if, for example, you've defined a function like echo
which conflicts with another package they may be using.
This is why Wildcard imports are clearly frowned upon in PEP8. From the document:
Wildcard imports (from <module> import *) should be avoided, as they make it unclear which names are present in the namespace, confusing both readers and many automated tools.
In any case, please don't worry yourself over things like this. It's only an issue if the user of your module doesn't follow PEP8, and they should probably be shown the errors of their ways anyway. Remember, in Python, We're all consenting adults here
.
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