Я никогда не замечал __path__
атрибут, который определяется на некоторых моих пакетах прежде сегодня. Согласно документации:
Пакеты поддерживают еще один специальный атрибут,
__path__
. Это инициализируется, чтобы быть списком, содержащим название каталога, содержащего пакет__init__.py
прежде чем код в том файле выполнен. Эта переменная может быть изменена; выполнение так влияет на будущее, ищет модули и подпакеты, содержавшиеся в пакете.В то время как эта функция не часто необходима, она может использоваться для расширения набора модулей, найденных в пакете.
Кто-то мог объяснить мне, что точно это означает и почему я когда-либо хотел бы использовать его?
Это обычно используется с pkgutil , чтобы позволить разместить пакет по диск. Например, zope.interface и zope.schema - это отдельные дистрибутивы ( zope
- это «пакет пространства имен»). У вас может быть установлен zope.interface в /usr/lib/python2.6/site-packages/zope/interface/
, в то время как вы используете zope.schema более локально в / home / me / src / myproject / lib / python2.6 / site-packages / zope / schema
.
Если вы поместите pkgutil.extend_path (__ path__, __name __)
в /usr/lib/python2.6/site-packages/zope / __ init__.py
, то будут импортированы и zope.interface, и zope.schema, потому что pkgutil изменит __ path __
на ['/ usr / lib / python2.6 / site-packages / zope', '/home/me/src/myproject/lib/python2.6/site-packages/zope'
.
pkg_resources.declare_namespace
(часть Setuptools) похож на pkgutil.extend_path
, но более осведомлен о zip-файлах на пути.
Ручное изменение __ path __
редко и, вероятно, не обязательно, хотя полезно смотреть на переменную при отладке проблем импорта с пакетами пространств имен.
Вы также можете использовать __ path __
для исправления monkeypatching, например, я время от времени исправляю distutils, создавая файл distutils / __ init __. Py
, который находится на ранней стадии 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...
Если вы измените __ путь __
, вы можете заставить интерпретатор искать в другом каталоге модули, принадлежащие этому пакету.
Это позволит вам, например, загружать разные версии одного и того же модуля в зависимости от условий выполнения. Вы можете сделать это, если хотите использовать разные реализации одной и той же функциональности на разных платформах.
В дополнение к выбору различных версий модуля на основе условий выполнения, как сказано в Syntactic , эта функциональность также позволит вам разбить ваш пакет на несколько частей / загрузок / устанавливает, сохраняя вид единого логического пакета.
Учтите следующее.
mypkg
и _mypkg_foo
. _mypkg_foo
содержит дополнительный модуль для mypkg
, foo.py
. mypkg
не содержит foo.py
. mypkg
__ init __. Py
может делать что-то вроде этого:
try:
import _mypkg_foo
__path__.append(os.path.abspath(os.path.dirname(_mypkg_foo.__file__)))
import mypkg.foo
except ImportError:
pass
Если кто-то установил пакет _mypkg_foo
, то mypkg.foo
им доступен. Если нет, то его не существует.