I had never noticed the __path__
attribute that gets defined on some of my packages before today. According to the documentation:
Packages support one more special attribute,
__path__
. This is initialized to be a list containing the name of the directory holding the package’s__init__.py
before the code in that file is executed. This variable can be modified; doing so affects future searches for modules and subpackages contained in the package.While this feature is not often needed, it can be used to extend the set of modules found in a package.
Could somebody explain to me what exactly this means and why I would ever want to use it?
This is usually used with pkgutil to let a package be laid out across the disk. E.g., zope.interface and zope.schema are separate distributions (zope
is a "namespace package"). You might have zope.interface installed in /usr/lib/python2.6/site-packages/zope/interface/
, while you are using zope.schema more locally in /home/me/src/myproject/lib/python2.6/site-packages/zope/schema
.
If you put pkgutil.extend_path(__path__, __name__)
in /usr/lib/python2.6/site-packages/zope/__init__.py
then both zope.interface and zope.schema will be importable because pkgutil will have change __path__
to ['/usr/lib/python2.6/site-packages/zope', '/home/me/src/myproject/lib/python2.6/site-packages/zope']
.
pkg_resources.declare_namespace
(part of Setuptools) is like pkgutil.extend_path
but is more aware of zips on the path.
Manually changing __path__
is uncommon and probably not necessary, though it is useful to look at the variable when debugging import problems with namespace packages.
You can also use __path__
for monkeypatching, e.g., I have monkeypatched distutils at times by creating a file distutils/__init__.py
that is early on sys.path
:
import os
stdlib_dir = os.path.dirname(os.__file__)
real_distutils_path = os.path.join(stdlib_dir, 'distutils')
__path__.append(real_distutils_path)
execfile(os.path.join(real_distutils_path, '__init__.py'))
# and then apply some monkeypatching here...