Chuck Chuck - 3 months ago 9
Python Question

What do I need to place in my `__init__.py` files to simplify this package's interface?

I have a package that works with the following files:

# package/sub1/obj1.py
class Obj1:
pass

# package/sub2/obj2.py
from ..sub1.obj1 import Obj1
class Obj2(Obj1):
pass


Currently, with a file at the same level as the
package
folder, I need to do this:

from package.sub1.ob1 import Obj1
from package.sub2.ob2 import Obj2


I want to be able to use the following:

from package.sub1 import Obj1 # can reference package.sub1.Obj1
from package.sub2 import Obj2 # can reference package.sub2.Obj2
from package import * # Can reference both


I know I need to edit one or more of the three existing
__init__.py
files, and I think I'll need to set the
__all__
variable in one or more of them, but I can't seem to figure out what the proper use is for what I want. Am I going about this incorrectly?

Answer

You could make it work by adding the following to your __init__.py files:

In package/sub1/__init__.py:

from .ob1 import Obj1

In package/sub2/__init__.py:

from .ob2 import Obj2

In package/__init__.py:

__all__ = ['sub1', 'sub2']

Now top-level code can do any the imports you asked about and they'll make package.subX.ObjX a valid name.

Is this a good design? Not really. One of the principles of good Python design is that "flat is better than nested". As user2357112 commented, unlike some other languages, Python doesn't require each class to have its own file. Since you want the Obj1 and Obj2 classes to be accessible from the package.sub1 and package.sub2 namespaces, respectively, it might make more sense to combine the files from the subX folders into a single subX.py file (replacing the subpackage with a single larger module).

Comments