You do not want to do this because you find that you have violated your code.
Python is a dynamic language, introspection gives us unlimited access to everything that a translator can achieve. This also applies to your module.
If you feel better, then the same applies to the standard library:
>>> import unittest >>> unittest.sys <module 'sys' (built-in)> >>> unittest.types <module 'types' from '/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/types.pyc'> >>> dir(unittest) ['FunctionTestCase', 'TestCase', 'TestLoader', 'TestProgram', 'TestResult', 'TestSuite', 'TextTestRunner', '_CmpToKey', '_TextTestResult', '_WritelnDecorator', '__all__', '__author__', '__builtins__', '__doc__', '__email__', '__file__', '__metaclass__', '__name__', '__package__', '__unittest', '__version__', '_makeLoader', '_strclass', 'defaultTestLoader', 'findTestCases', 'getTestCaseNames', 'main', 'makeSuite', 'os', 'sys', 'time', 'traceback', 'types']
All that the module needs, the global namespace, can be seen from the outside. This is normal .
As you have already discovered, use __all__ to control the wildcard import from modulename import * and leave your module namespace otherwise.
Of course, if you want to provide users of your package with a clean API, there is nothing that will stop you from importing the names that are part of the API into the top-level package __init__.py or using api.py
Importing only means adding the same name as the variable in the current module; mod_2.numpy is the same as sys.modules['numpy'] , or numpy in your current module after running import numpy .