Maintain an unoccupied namespace

tl; dr: How to create a new namespace in some __init__.py and copy the checkboxes for selecting a different namespace into it without requiring a submodule in the new directory?

Full question:

Let's say I have a couple of modules in a package with a directory structure as follows:

 foo/mod_1.py foo/mod_2.py foo/__init__.py 

mod_1.py looks like this:

 import numpy __all__ = ['test1'] def test1(): return numpy.zeros(10) 

mod_2.py looks like this:

 import numpy def test2(): return numpy.zeros(20) 

and __init__.py as follows:

 from mod_1 import * import mod_2 del mod_1 

This gives a more or less desirable namespace:

 In [7]: dir(foo) Out[7]: ['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', 'mod_2', 'test1'] 

Except numpy now in the foo.mod_2 namespace. If I try to remove it in __init__.py , with del mod_2.numpy , it no longer exists for this module, so mod_2.test2 does not work.

I can achieve what I want by creating an additional mod_2 directory containing mod_2.py , but I want to keep the directory structure as is, if possible.

Hence my initial question.

Edit: I don't mind making a little name to stop one name stepping on another. Let them say that we put the corresponding bits of mod_2.py in foo._mod_2 .

+4
source share
1 answer

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 .

+3
source

All Articles