Friday, August 13, 2010

 

Python package pattern

I first saw this pattern in pyObjC, although I am sure it's implemented elsewhere. The basic idea is, if I have package a:

a/
  __init__.py
  clsa.py
  clsb.py

To get at the module in clsa.py, I'll import a.clsa. But what if you want to present a different interface for your package?

Imports are like anything else. They wind up in the dictionary of the containing namespace. Import sys, then dir() - sys appears, as a module object. The same happens in modules themselves. Imports, like global variables, appear in the namespace of the module and so are accessible via the module object.

As an example of this, try:

>>> import os
>>> dir(os)
>>> os.sys
>>> print os.sys.version

The os module imports sys, so we can actually access sys via os.sys. Python's importer is smart enough to give us two different references to the same object, rather than actually importing another copy of sys (if you already have sys imported).

So what does this mean? Well, if you wanted to give the example package above a flatter view, you could edit __init__.py:
from clsa import someclass
import clsa
import clsb

With the above __init__.py, you'll have a package that works as follows:
>>> import a
>>> a.clsa.somefunc() # would traverse the clsa import in __init__.py
>>> instance = a.someclass() # this uses the someclass import from clsa directly

In larger packages, this allows you to expose interesting classes to the user while still keeping everything organized in separate modules.

Labels: ,


This page is powered by Blogger. Isn't yours?