Расширить путь поиска Python до другого источника


107

Я только что присоединился к проекту с довольно большой существующей кодовой базой. Мы разрабатываем в linux и не используем и IDE. Запускаем через командную строку. Я пытаюсь понять, как заставить python искать правильный путь при запуске модулей проекта. Например, когда я запускаю что-то вроде:

python someprojectfile.py

я получил

ImportError: no module named core.'somemodule'

Я получаю это для всего моего импорта, чтобы предположить, что это проблема с путем.

TL; DR:

Как мне заставить Python искать ~/codez/project/и все файлы и папки для файлов * .py во время операторов импорта.

Ответы:


172

Есть несколько возможных способов сделать это:

  • Задайте для переменной среды PYTHONPATHсписок каталогов, разделенных двоеточиями, для поиска импортированных модулей.
  • В вашей программе используйте, sys.path.append('/path/to/search')чтобы добавить имена каталогов, в которых Python будет искать импортированные модули. sys.path- это просто список каталогов, которые Python ищет каждый раз, когда ему предлагается импортировать модуль, и вы можете изменить его по мере необходимости (хотя я бы не рекомендовал удалять какие-либо стандартные каталоги!). Любые каталоги, которые вы помещаете в переменную среды, PYTHONPATHбудут вставлены sys.pathпри запуске Python.
  • Используйте site.addsitedirдля добавления каталога в sys.path. Разница между этим и простым добавлением заключается в том, что при использовании addsitedirон также ищет .pthфайлы в этом каталоге и использует их для возможного добавления дополнительных каталогов в sys.pathзависимости от содержимого файлов. Смотрите документацию для более подробной информации.

Какой из них вы хотите использовать, зависит от вашей ситуации. Помните, что когда вы распространяете свой проект среди других пользователей, они обычно устанавливают его таким образом, что файлы кода Python будут автоматически обнаруживаться импортером Python (т. Е. Пакеты обычно устанавливаются в site-packagesкаталог), поэтому, если вы вмешиваетесь sys.pathв свой код , что может быть ненужным и может даже иметь неблагоприятные последствия при запуске этого кода на другом компьютере. Что касается разработки, я бы рискнул предположить, что настройка PYTHONPATHобычно - лучший выход.

Однако, когда вы используете что-то, что работает на вашем собственном компьютере (или когда у вас нестандартные настройки, например, иногда в рамках веб-приложений), нередко делать что-то вроде

import sys
from os.path import dirname
sys.path.append(dirname(__file__))

Итак, если бы у меня было, скажем, 15 подкаталогов, мне пришлось бы добавлять каждый по отдельности?
themaestro

и не могли бы вы привести пример аргумента командной строки для изменения PYTHONPATH?
themaestro

3
Чтобы установить PYTHONPATH: in .bashrcили любой другой файл запуска, который использует ваша оболочка (если это не Bash), напишите export PYTHONPATH=$PYTHONPATH:$HOME/codez/project. Но если у вас есть куча подкаталогов, я бы создал .pthфайл и использовал site.addsitedir. Вы можете создать модуль, sitecustomizeкоторый будет вызывать функцию за вас; попробуйте поместить его ~/.local/lib/python2.6/sitecustomize.py(замените свою версию Python), чтобы он, надеюсь, автоматически импортировался.
David Z

Я поместил следующее в свой файл .bashrc, и мне все еще не везет с этим импортом. Любые идеи? Как бы мне вообще сделать файл .pth? экспорт PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / export PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / экспорт проекта PYTHONPATH = $ PYTHONPATH $: $ HOME / adaifotis / codez / project / project HOME / adaifotis / codez / project / proxies export PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / project / conf
themaestro

Попробуйте открыть терминал и запустить echo $PYTHONPATH. Если переменная среды была установлена ​​правильно, вы должны увидеть список каталогов, разделенных двоеточиями. Для получения информации о .pthфайлах см. Документацию по siteмодулю, на который я ссылался в своем ответе. Он сообщает вам, каким должно быть содержимое и как его использовать.
David Z

13

Вы также должны прочитать о пакетах python здесь: http://docs.python.org/tutorial/modules.html .

Из вашего примера я могу предположить, что у вас действительно есть пакет в ~/codez/project. Файл __init__.pyв каталоге python отображает каталог в пространство имен. Если все ваши подкаталоги имеют __init__.pyфайл, вам нужно только добавить базовый каталог в свой PYTHONPATH. Например:

PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / project

Как объясняет Дэвид, помимо тестирования переменной среды PYTHONPATH, вы можете протестировать ее на Python следующим образом:

$ python
>>> import project                      # should work if PYTHONPATH set
>>> import sys
>>> for line in sys.path: print line    # print current python path

...


Вы можете поставить __init__.pyобратные кавычки, чтобы было ясно, что вы действительно имеете в виду __init__.py, а не init.py. Просто чтобы не запутать новичков. :)
antred

4

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

В моем проекте у меня был основной сценарий в родительском каталоге, и, чтобы различать модули, я поместил все вспомогательные модули в подпапку под названием «modules». В моем основном сценарии я импортирую эти модули следующим образом (для модуля с именем report.py):

from modules.report import report, reportError

Если я вызываю свой основной сценарий, это работает. ОДНАКО, я хотел протестировать каждый модуль, включив main()в каждый и вызывая каждый напрямую, как:

python modules/report.py

Теперь Python жалуется, что не может найти «модуль с именем modules». Ключевым моментом здесь является то, что по умолчанию Python включает папку скрипта в свой путь поиска, НО НЕ CWD. На самом деле эта ошибка говорит: «Я не могу найти подпапку модулей». Это связано с тем, что в каталоге, где находится модуль report.py, нет подкаталога «modules».

Я считаю, что лучшим решением этой проблемы является добавление CWD в путь поиска Python, включив его вверху:

import sys

sys.path.append(".")

Теперь Python просматривает CWD (текущий каталог), находит подпапку «modules», и все в порядке.


3

Я прочитал этот вопрос в поисках ответа, и мне не понравился ни один из них.

Поэтому я написал быстрое и грязное решение. Просто поместите это где-нибудь в свой sys.path, и он добавит любой каталог folder(из текущего рабочего каталога) или в abspath:

#using.py

import sys, os.path

def all_from(folder='', abspath=None):
    """add all dirs under `folder` to sys.path if any .py files are found.
    Use an abspath if you'd rather do it that way.

    Uses the current working directory as the location of using.py. 
    Keep in mind that os.walk goes *all the way* down the directory tree.
    With that, try not to use this on something too close to '/'

    """
    add = set(sys.path)
    if abspath is None:
        cwd = os.path.abspath(os.path.curdir)
        abspath = os.path.join(cwd, folder)
    for root, dirs, files in os.walk(abspath):
        for f in files:
            if f[-3:] in '.py':
                add.add(root)
                break
    for i in add: sys.path.append(i)

>>> import using, sys, pprint
>>> using.all_from('py') #if in ~, /home/user/py/
>>> pprint.pprint(sys.path)
[
#that was easy
]

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


3

Самый простой способ, который я нашел, - это создать файл "any_name.pth" и поместить его в свою папку "\ Lib \ site-packages". Вы должны найти эту папку везде, где установлен Python.

В этом файле поместите список каталогов, в которых вы хотите хранить модули для импорта. Например, сделайте в этом файле такую ​​строку:

C: \ Users \ пример ... \ пример

Вы сможете убедиться, что это работает, запустив это в python:

import sys
for line in sys: print line

Вы увидите распечатанный каталог, среди прочего, откуда вы также можете импортировать. Теперь вы можете импортировать файл mymodule.py, который находится в этом каталоге, так же просто, как:

import mymodule

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


0

Новый вариант для старого вопроса.
Установка fail2banпакета на Debian выглядит так, как будто он жестко запрограммирован для установки /usr/lib/python3/dist-packages/fail2banне на python3 sys.path.


> python3
Python 3.7.3 (v3.7.3:ef4ec6ed12, Jun 25 2019, 18:51:50)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/usr/lib/python37.zip', '/usr/lib/python3.7', '/usr/lib/python3.7/lib-dynload', '/usr/lib/python3.7/site-packages']
>>>

поэтому вместо простого копирования я (bash) связал библиотеку с более новыми версиями.
Будущие обновления исходного приложения также будут автоматически применены к связанным версиям.

 if [ -d /usr/lib/python3/dist-packages/fail2ban ]
   then
      for d in /usr/lib/python3.*
      do
         [ -d ${d}/fail2ban ] || \
            ln -vs /usr/lib/python3/dist-packages/fail2ban ${d}/
      done
   fi
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.