I've scraped up another sack of sweets, tanked up my keyboard with a fresh Oxygen font and ready to tell stories about writing a code compatible with Python 2.4-2.7 versions using only standard libraries.
Sometimes modules have to be imported dynamically. Yes, yes, let in your little cozy kawaii code something that you don't even know by name.
Python 2.4+ has the imp library that takes in your guests, cleans their boots and shows their places. But Python 3.1+ trained another guard the importlib and made the imp retire from the Python version 3.4.
No one wants to use deprecated libraries. So no guards! Let's be good hosts by ourselves.
The sys library has the sys.path attribute, that contains all module search paths, default and specified via the PYTHONPATH environment variable.
import sys sys.path >>> ['', '/usr/bin', '/something/from/env/variable', '/usr/lib64/python27.zip', '/usr/lib64/python2.7', '/usr/lib64/python2.7/plat-linux2', '/usr/lib64/python2.7/lib-tk', '/usr/lib64/python2.7/lib-old', '/usr/lib64/python2.7/lib-dynload', '/usr/lib64/python2.7/site-packages', '/usr/lib64/python2.7/site-packages/gtk-2.0', '/usr/lib/python2.7/site-packages', '/usr/lib/python2.7/site-packages/IPython/extensions']
And it's possible to add your own path to sys.path in your code:
import sys import os module_path = '../module_dir/module' sys.path.append(os.path.realpath(os.path.dirname(module_path)))
The os.path.realpath method is used to convert symlinks and relative paths to absolute ones.
Note, that os.path.realpath cuts the trailing slash. It doesn't matter for the example above, but can be painful while processing paths that can end with a directory. In these situations os.path.dirname should be called before os.path.realpath, otherwise one level of the directory tree will be missed.
And now it's time to say “Hello, dear guest!”
# Obtain the module name and remove its extension if any module_name = os.path.splitext(os.path.basename(module_path)) # End this! try: module_var = __import__(module_name) except ImportError: print "Error: The module cannot be imported."
Short circuit conditions
Sometimes I have a great notion… to feel self fashionable, contemporary, hipster and write something long and artistic using list comprehensions:
[light + ' is black' if light in pierre_soulages else light + ' is a wave' for light in art_and_science]
But Python 2.4 is an utilitarian language for writing of good programs, not good poems and it doesn't support shortcut conditional expressions. So if you want to write a poem just wrap the condition up in a small auxiliary function:
def write_poem(word): if rhyme(word): return word else: return 'shm' + word[1:] new_poem = [write_poem(w) for w in text]
Of course, if you're an adept of Conceptual art, logical operators are always at your service.
Sometimes it's necessary to send some nontrivial configuration information to the script. The conventional way to do it is to use JSON or YAML. Python has no standard tools for YAML support. So JSON is the only choice or would be it, if the standard json library appeared in the Python version earlier than 2.6. There is the third-party simplejson library that is spread sufficiently to rely on the assumption that it's installed on most of machines with old Python versions. But simplejson stopped supporting Python 2.4 some versions ago. It's still possible to install simplejson under Python 2.4 but with some pain as a bonus.
I found no panacea for this. I just cowardly dropped users of the Python 2.4 with no simplejson installed from a part of absolutely-not-so-important functionality.
try: import json except ImportError: try: import simplejson as json except ImportError: print "Sorry. No milk for you."
But if the configuration object is not too sophisticated, alternative methods can be tried, e.g. good old ini files.
Well, my sack looks empty. Oh, I'm lying! There are useful links on its bottom:
The bunch of recipes for module importing
The birth of the shortcut conditional expression
Old snakes. Part I
Where the black lights are