Every now and then I was working in Python I needed to dynamically import some modules cause I like declarative style and importing and using only modules that I really need depending on the configuration while executing the program. Dynamical module loading helps better granularization of code by breaking a big script into topic related significant modules that are executed only if needed by program and thus easier maintenance. Lets say we have a system that calls different modules that manifest different behaviour connected with different data formats. If we don’t request noted system to load and parse XML we don’t need XML parsing module, etc… This is just an example. I’m not speaking about installed library dependencies but about little modules loaded relative to the location of the script that imports them.
Let’s say we have this structure:
system/
main.py
lang/
js.py
java.py
php.py
…
If I call the main script like and pass it an argument: python system/main.py js,php
And lets say every module has a function called fn that we want to use depending on a context. I want to load modules inside main but only the ones I noted and it can look something like this:
lang = {}
for l in sys.argv[1].split(‘,’):
mod = importFromURI(os.path.join(‘lang’, l))
if mod is not None:
lang[l] =mod.fn
And then later we can use loaded and declared functions in lang depending on the context, for example:
if file_ext in lang:
lang[file_ext](source_file)
The importFromURI is a very simple sugar function, a wrapper for imp module used to implement import statement. It will break the supplied URI and load the module relative from the stript that implemented the function. If you pass True for the second argument, URI will be considered as it is, absolute or relative to the working directory. If the import fails because of nonexistent URI or import breaks for some reason, this function will return None.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import imp | |
def importFromURI(self, uri, absl=False): | |
if not absl: | |
uri = os.path.normpath(os.path.join(os.path.dirname(__file__), uri)) | |
path, fname = os.path.split(uri) | |
mname, ext = os.path.splitext(fname) | |
no_ext = os.path.join(path, mname) | |
if os.path.exists(no_ext + '.pyc'): | |
try: | |
return imp.load_compiled(mname, no_ext + '.pyc') | |
except: | |
pass | |
if os.path.exists(no_ext + '.py'): | |
try: | |
return imp.load_source(mname, no_ext + '.py') | |
except: | |
pass |
To sum it up, this function enables you to load python scripts and modules into your code whenever you need by passing the path with filename.
very good method for “plugins” use.