2

I have a directory structure:

example.py
templates/
    __init__.py
    a.py
    b.py

a.py and b.py have only one class, named the same as the file (because they are cheetah templates). For purely style reasons, I want to be able to import and use these classes in example.py like so:

import templates

t = templates.a()

Right now I do that by having this in the template folder's __init__.py:

__all__ = ["a", "b"]
from . import *

However, this seems pretty poor (and maybe superfluous), and doesn't even do what I want, as I have to use the classes like this:

t = templates.a.a()

Thoughts?

colinmarc
  • 2,421
  • 1
  • 22
  • 34

3 Answers3

4

To avoid repeating from <whatever> import * 25 times, you need a loop, such as:

import sys

def _allimports(modnames)
  thismod = sys.modules[__name__]

  for modname in modnames:
    submodname = '%s.%s' % (thismod, modname)
    __import__(submodname)
    submod = sys.modules[submodname]
    thismod.__dict__.update(submod.__dict__)

_allimports('a b c d e'.split())  # or whatever

I'm putting the meaningful code in a function because (a) it's always best [[for performance and to avoid polluting the module's namespace]], (b) in this particular case it also avoids accidents (e.g., some submodule might define a name thismod or modnames... so it's important to keep those names that we're using in the loop local to the function, not module globals, so they can't be accidentally trampled;-).

If you want to enforce the fact that a module named modname only has one class (or other global) with the same name, change the last statement of the loop to:

    setattr(thismod, modname, getattr(submod, modname))
Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • thanks! any thoughts on whether what I'm trying to do/what I have now is a good idea at all? – colinmarc Jun 12 '10 at 02:04
  • @colinmarc, I approve of your being skeptical about using such (deep) introspection / (slight) metaprogramming in production code, but you don't really have much of an alternative here -- the `a.py` &c files with class `a` are (I believe) a Cheetah given, and asking users to always do `from templates import a` (&c) then use `a.a()` (&c) does feel somewhat redundant (I might go for it, but only because I'm an evangelist for "always import a **module** -- **never** a package, **never** anything from _inside_ a module" and a sworn enemy of `import *`...;-) -- most people are more reasonable!-) – Alex Martelli Jun 12 '10 at 02:21
  • @colinmarc, sure, if you can have all the classes in a `template.py` in lieu of the current `template` directory/package, that will be much simpler. – Alex Martelli Jun 12 '10 at 04:24
3

In your __init__.py:

from a import *
from b import *

Now all of a's contents will be in templates, as will all of b's contents.

Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
3

I didn't even know you could have from . import *. My python interpreter complains about such statements. Still, to your problem, you could do:

# __init__.py
from . import a, b
a = a.a
b = a.b

you can now use

# example.py
import templates
t = templates.a()

other solution:

# __init__.py
from a import *
from b import *
Miguel Ventura
  • 10,344
  • 2
  • 31
  • 41