Lazy imports (was Re: module naming)
Peter Funk
pf at artcom-gmbh.de
Tue Apr 18 07:59:29 EDT 2000
Hi!
> On Mon, 17 Apr 2000, David Arnold wrote:
> > what about something like
> >
> > from Record import Record
> > from Field import Field
> > from IdxDict import IdxDict
> >
> > in your zdc/__init__.py ?
[...]
Michal Wallace (sabren) asks:
> That's certainly a lot cleaner! But is there a way to do that and
> not have it load each one of those files every time? There's actually
> more than 3, and even though they're all fairly small, I'd rather not
> have the overhead of loading them until they're needed.
You could try to adopt the lazy loader concept implemented in
the Pmw package. The idea is to use a small tool, that builds a
dictionary of exported features (classes and more) by investigating
all module files in the package and places this in a file called
for example 'exports.def'. Than you can use the following
__init__.py file to load features (classes, constants, functions,
or modules, what you want) on demand. The idea is "stolen" from
Greg McFarlanes wonderful Pmw package:
Regards, Peter
---- 8< ---- 8< ---- cut here ---- 8< ---- schnipp ---- 8< ---- schnapp ----
#!/usr/bin/env python
## vim:ts=4:et:nowrap
"""__init__ : This file is executed when the package is imported. It creates
a lazy importer/dynamic loader for the package and replaces the package
module with it. This is a very simplified version of the loader supplied
with Pmw. All the package version management has been stripped off."""
import sys, os, string, types
_EXP_DEF = 'exports.def' # export definition file
_BASEMODULE = 'base' # Name of Base module for the package
class _Loader:
"""An instance of this class will replace the module in sys.modules"""
def __init__(self, path, package):
self._path, self._package = path, package
self._initialised = 0
def _getmodule(self, modpath):
__import__(modpath)
mod = sys.modules[modpath]
return mod
def _initialise(self):
# Create attributes for the Base classes and functions.
basemodule = self._getmodule('_'+self._package+'.'+_BASEMODULE)
for k,v in basemodule.__dict__.items():
if k[0] is not '_' and type(v) != types.ModuleType:
self.__dict__[k] = v
# Set the package definitions from the exports.def file.
dict = {
'_features' : {},
'_modules' : {},
}
for name in dict.keys():
self.__dict__[name] = {}
d = {}
execfile(os.path.join(self._path, _EXP_DEF), d)
for k,v in d.items():
if dict.has_key(k):
if type(v) == types.TupleType:
for item in v:
## modpath = self._package + item
modpath = item
dict[k][item] = modpath
elif type(v) == types.DictionaryType:
for k1, v1 in v.items():
## modpath = '_'+self._package +'.'+ v1
modpath = v1
dict[k][k1] = modpath
self.__dict__.update(dict)
self._initialised = 1
def __getattr__(self, name):
"""This will solve references to not yet used features"""
if not self._initialised:
self._initialise()
# Beware: _initialise may have defined 'name'
if self.__dict__.has_key(name):
return self.__dict__[name]
# The requested feature is not yet set. Look it up in the
# tables set by exports.def, import the appropriate module and
# set the attribute so that it will be found next time.
if self._features.has_key(name):
# The attribute is a feature from one of the modules.
modname = self._features[name]
mod = self._getmodule('_'+self._package+'.'+modname)
feature = getattr(mod, name)
self.__dict__[name] = feature
return feature
elif self._modules.has_key(name):
# The attribute is a module
mod = self._getmodule('_'+self._package+'.'+name)
self.__dict__[name] = mod
return mod
else:
# The attribute is not known by the package, report an error.
raise AttributeError, name
# Retrieve the name of the package:
_package = os.path.split(__path__[0])[1]
# Rename (hide) the original package for later perusual:
sys.modules['_'+_package] = sys.modules[_package]
# Create the dynamic loader and install it into sys.modules:
sys.modules[_package] = _Loader(__path__[0], _package)
More information about the Python-list
mailing list