WEBINAR:
On-Demand
Building the Right Environment to Support AI, Machine Learning and Deep Learning

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:
aaa (package)
|-- __init__.py
|-- a.py
|-- aa.py
Here is the content of the modules:
__init__.py
-----------
print 'aaa/__init__ here'
a.py
----
from __future__ import absolute_import
print 'aaa/a here'
import aa
aa.py
-----
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.
import_test.py
-----------
print 'import_test here'
import aaa.a
aa.py
-----
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:
aaa/__init__ here
aaa/a here
aa here
If I comment out the
__future__ line the local
aaa/aa.py module will be imported from
aaa.a.py:
aaa/__init__ here
aaa/a here
aaa/aa here
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:
aaa/a.py
---------
from __future__ import absolute_import
print r'aaa/a here'
import aa
from . import aa
Output (of
import_test.py):
import_test here
aaa/__init__ here
aaa/a here
aa here
aaa/aa here
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