Для чего нужен __path__? - PullRequest
       6

Для чего нужен __path__?

53 голосов
/ 23 апреля 2010

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

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

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

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

Ответы [ 4 ]

31 голосов
/ 23 апреля 2010

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

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

30 голосов
/ 23 апреля 2010

Обычно это используется с 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.схема будет импортирована, потому что 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, но больше осведомлено о почтовых индексах на пути.

Ручное изменение __path__ является редкостью и, вероятно, не является обязательным, хотя полезно смотреть на переменную при отладке проблем импорта с пакетами пространств имен.

Вы также можете использовать __path__ для обезьяньего патчаНапример, иногда я запускал 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...
7 голосов
/ 23 апреля 2010

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

Учтите следующее.

  • У меня есть два пакета, mypkg и _mypkg_foo.
  • _mypkg_foo содержит дополнительный модуль для mypkg, foo.py.
  • после загрузки и установки, mypkg не содержит foo.py.

mypkg __init__.py может сделать что-то вроде этого:1025 *

Если кто-то установил пакет _mypkg_foo, то ему доступно mypkg.foo.Если нет, его не существует.

0 голосов
/ 04 декабря 2014

Особая ситуация, с которой я столкнулся, - это когда пакет становится достаточно большим, и я хочу разделить его части на подкаталоги без необходимости изменения кода, ссылающегося на него.

Например, у меня естьпакет под названием views, который собирал ряд вспомогательных служебных функций, которые путались с основным назначением пакета верхнего уровня.Я смог переместить эти вспомогательные функции в подкаталог utils и добавить следующую строку в __init__.py для пакета views:

__path__.append(os.path.join(os.path.dirname(__file__), "utils"))

С этим изменением тоже views/__init_.py я мог бызапустите остальную часть программного обеспечения с новой файловой структурой без каких-либо дальнейших изменений в файлах.

(я пытался сделать нечто подобное с операторами import в файле views/__init__.py, но с модулями подпакетавсе еще не были видны при импорте пакета view - я не совсем уверен, что я что-то там упустил; комментарии к этому приветствию!)

(Этот ответ основан на установке Python 2.7)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...