Для чего __ путь __ полезен?

Я никогда не замечал __path__ атрибут, который определяется на некоторых моих пакетах прежде сегодня. Согласно документации:

Пакеты поддерживают еще один специальный атрибут, __path__. Это инициализируется, чтобы быть списком, содержащим название каталога, содержащего пакет __init__.py прежде чем код в том файле выполнен. Эта переменная может быть изменена; выполнение так влияет на будущее, ищет модули и подпакеты, содержавшиеся в пакете.

В то время как эта функция не часто необходима, она может использоваться для расширения набора модулей, найденных в пакете.

Кто-то мог объяснить мне, что точно это означает и почему я когда-либо хотел бы использовать его?

53
задан SilentGhost 23 April 2010 в 06:32
поделиться

3 ответа

Это обычно используется с 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...
31
ответ дан 7 November 2019 в 08:49
поделиться

Если вы измените __ путь __ , вы можете заставить интерпретатор искать в другом каталоге модули, принадлежащие этому пакету.

Это позволит вам, например, загружать разные версии одного и того же модуля в зависимости от условий выполнения. Вы можете сделать это, если хотите использовать разные реализации одной и той же функциональности на разных платформах.

32
ответ дан 7 November 2019 в 08:49
поделиться

В дополнение к выбору различных версий модуля на основе условий выполнения, как сказано в 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 им доступен. Если нет, то его не существует.

7
ответ дан 7 November 2019 в 08:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: