Для чего полезен __path__?

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

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

  • Путь Python для клонирования git-репозитория
  • Python: доступ к «областям модуля» vars
  • почему я должен помещать код python в файлы __init__.py
  • itertools.ifilter Vs. фильтр Vs. список понятий
  • класс не определен, несмотря на импорт
  • Что такое. в заявлении на импорт в Python?
  • Хотя эта функция часто не нужна, ее можно использовать для расширения набора модулей, найденных в пакете.

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

  • Генерировать случайные числа с заданным (численным) распределением
  • Почему значение __name__ меняется после присвоения sys.modules ?
  • почему я должен помещать код python в файлы __init__.py
  • Что такое замороженный модуль Python?
  • Что такое. в заявлении на импорт в Python?
  • Путь Python для клонирования git-репозитория
  • 4 Solutions collect form web for “Для чего полезен __path__?”

    Обычно это используется с 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 но больше знает об zips на пути.

    Вручную изменение __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... 

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

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

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

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

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

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

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

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

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

    Python - лучший язык программирования в мире.