Розгорніть Шлях пошуку Python до іншого джерела


106

Я щойно приєднався до проекту з досить великою існуючою базою коду. Ми розробляємось в Linux і не використовуємо і IDE. Пробігаємося через командний рядок. Я намагаюся розібратися, як змусити пітон шукати правильний шлях під час запуску модулів проекту. Наприклад, коли я запускаю щось на кшталт:

python someprojectfile.py

я отримав

ImportError: no module named core.'somemodule'

Я отримую це за весь мій імпорт, я вважаю, що це проблема зі шляху.

TLDR:

Як змусити Python шукати ~/codez/project/всі файли та папки для файлів * .py під час імпорту операторів.

Відповіді:


171

Є кілька можливих способів зробити це:

  • Встановіть змінну оточуючого середовища 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: у .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 / експортувати PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / проект експорту PYTHONPATH = $ PYTHONPATH: $ HOME / adaifotis / codez / проектz / corez / проект / corep / проектPPYPONY / PAPTONY / PAPTONY / PAPTONY / PAPTONY / PAPTONY / PAPTONY / PAPTONY / PAPTONY / PAPTONY / PATTHONTATH / PAPTONY PATTHPATH = PYTHONPATH HOME / adaifotis / codez / проект / проксі-експорт 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 / проект

На додаток до тестування змінної середовища 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

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

У своєму проекті у мене був головний скрипт у батьківському каталозі, і, щоб розмежувати модулі, я помістив усі підтримуючі модулі в підпапку під назвою "модулі". У своєму головному сценарії я імпортую такі модулі, як цей (для модуля під назвою report.py):

from modules.report import report, reportError

Якщо я називаю свій основний сценарій, це працює. ЗАРАЗ, я хотів перевірити кожен модуль, включивши main()в кожен і безпосередньо зателефонувавши як:

python modules/report.py

Тепер Python скаржиться, що не може знайти "модуль під назвою модулі". Ключовим тут є те, що за замовчуванням Python включає папку скрипту у свій шлях пошуку, АЛЕ НЕ CWD. Отже, що ця помилка говорить насправді, це "я не можу знайти підпапку модулів". Це тому, що в каталозі, де знаходиться модуль report.py, немає підкаталогу "модулі".

Я вважаю, що найкращим рішенням для цього є додавання CWD в шлях пошуку Python, включивши це вгорі:

import sys

sys.path.append(".")

Тепер Python здійснює пошук у CWD (поточний каталог), знаходить підпапку "модулі", і все добре.


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-пакети". Ви повинні знайти цю папку, де б не встановлено python.

У цей файл покладіть список каталогів, де ви хочете зберегти модулі для імпорту. Наприклад, зробіть рядок у цьому файлі таким чином:

С: \ Користувачі \ приклад ... \ Приклад

Ви зможете сказати, що це працює, запустивши це в 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.