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
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
.
This is really just a side-effect of the way that python modules work. Anything that you import into a module will be available as a top-level object in that module. Most people don't worry about it and simply use the canonical import path.