n my last article, "Drill-down on Three Major New Modules in Python 2.5 Standard Library
," I discussed how the ctypes, pysqlite, and ElementTree language modules can save you time and aggravation. In this, my third and final, article on the new 2.5 version of Python, I'll go over some additional language enhancements and modules that each, individually, adds an important ingredient to some of the smaller subsets of the Python community. I will also cover performance improvements, porting your code from previous versions of Python, and some other odds and ends that will be important to anyone who is ready to adopt the latest release of Python.
Absolute and Relative Imports
To get started, I'll run through some of the basics of Python language organization.
Python software is organized in modules (.py files) stored in packages. The modules may be pre-compiled (.pyc) or could be extension modules. Python packages are usually just directories that appear in sys.path. Sub-packages are sub-directories of a package directory (or other sub-package) that contain an __init__.py. If the __init__.py doesn't exist then the sub-directory is ignored by Python's import mechanism.
Python locates modules that you import by searching a list of directories (or zip files) stored in sys.path. This list is initialized with the directory of the running program, the contents of the PYTHONPATH environment variable, and a list of platform-dependent directories. Programs may modify sys.path at runtime to control the import behavior.
Prior to Python 2.5 imports were always relative to your sys.path. The algorithm was very simple:
When importing 'aaa.a' scan through sys.path. Try to import aaa.a.py from each entry in sys.path.
There were two problems with this algorithm:
- Local modules might shadow library modules with identical names. This becomes more of a problem as the standard library grows.
- Modules inside nested packages had to use the full path to import modules from a sibling package or parent package.
Python 2.5 added a __future__
option to change the import behavior in order to address these problems. I created a little package and a couple of helper modules to demonstrate the import behavior in Python 2.5:
Here is the content of the modules:
print 'aaa/__init__ here'
from __future__ import absolute_import
print 'aaa/a here'
print r'aaa\aa here'
I "installed" the package by copying it to Lib/site-packages (the location of third-party Python packages).
In addition I created two modules in the site-packages directory.
print 'import_test here'
print 'aa here'
Each module just prints its package (if in a package) and its name. It all starts with import_test.py
that imports aaa.a
. This results in the automatic import of aaa/__init__.py
and then aaa/a.py
. The latter, aaa/a.py
, is the interesting piece. It uses the new absolute_import
feature. It imports aa
. A module named aa.py
exists in the a.py
's directory (aaa) and in the site-packages directory. Without absolute_import
the local aa.py
would have been imported (aaa/a.py
), but the "absolute" aa.py
in site-packages is imported instead. Here is the output of running import_test.py
If I comment out the __future__
line the local aaa/aa.py
module will be imported from aaa.a.py
What if you want to import both the local aa
and the absolute aa
? Prior to Python 2.5 you would have had to play tricks and dynamically modify your sys.path
(and hopefully remember to restore it afterwards). With Python 2.5 you can use the new dot notation:
from __future__ import absolute_import
print r'aaa/a here'
from . import aa
Output (of import_test.py
The '.' allows you to import from the current directory. Double dot '..' can be used to import from a parent package in a relative path notation.
There is one caveat. The relative import syntax works inside packages only. If you try to use it in a main module you will get the following exception:
ValueError: Attempted relative import in non-package