Python: лучший способ добавить к sys.path относительно текущего запуска script
У меня есть каталог, полный скриптов (скажем project/bin
). У меня также есть библиотека, расположенная в project/lib
, и хочу, чтобы скрипты автоматически загружали ее. Это то, что я обычно использую в верхней части каждого script:
#!/usr/bin/python
from os.path import dirname, realpath, sep, pardir
import sys
sys.path.append(dirname(realpath(__file__)) + sep + pardir + sep + "lib")
# ... now the real code
import mylib
Это довольно громоздко, уродливо и должно быть вставлено в начале каждого файла. Есть ли лучший способ сделать это?
Действительно, на что я надеюсь, это что-то столь же гладко, как это:
#!/usr/bin/python
import sys.path
from os.path import pardir, sep
sys.path.append_relative(pardir + sep + "lib")
import mylib
Или, что еще лучше, что-то, что не сломается, когда мой редактор (или кто-то другой, кто имеет право доступа) решает переупорядочить импорт как часть процесса очистки:
#!/usr/bin/python --relpath_append ../lib
import mylib
Это не будет напрямую переноситься на платформы, отличные от posix, но это будет чистым.
Ответы
Ответ 1
Если вы не хотите редактировать каждый файл
- Установите библиотеку как обычный python libray
или
- Установите
PYTHONPATH
на lib
или если вы хотите добавить одну строку в каждый файл, добавьте оператор импорта вверху, например.
import import_my_lib
сохранить import_my_lib.py
в bin и import_my_lib
может корректно установить путь python к любому lib
, который вы хотите
Ответ 2
Это то, что я использую:
import os, sys
sys.path.append(os.path.join(os.path.dirname(__file__), "lib"))
Ответ 3
Я использую:
import sys,os
sys.path.append(os.getcwd())
Ответ 4
Создайте оберточный модуль project/bin/lib
, который содержит следующее:
import sys, os
sys.path.insert(0, os.path.join(
os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'lib'))
import mylib
del sys.path[0], sys, os
Затем вы можете заменить весь треск в верхней части ваших скриптов:
#!/usr/bin/python
from lib import mylib
Ответ 5
Если вы не хотите каким-либо образом изменять содержимое script, добавьте текущий рабочий каталог .
в $PYTHONPATH (см. пример ниже)
PYTHONPATH=.:$PYTHONPATH alembic revision --autogenerate -m "First revision"
И назовите это днем!
Ответ 6
Существует проблема с каждым ответом, который можно суммировать как "просто добавьте это магическое заклинание к началу вашего сценария. Посмотрите, что вы можете сделать только с одной строкой или двумя кодами". Они не будут работать во всех возможных ситуациях!
Например, одно из таких магических заклинаний использует файл. К сожалению, если вы упаковываете свой скрипт с помощью cx_Freeze или используете IDLE, это приведет к исключению.
В другом таком магическом заклинании используется os.getcwd(). Это будет работать, только если вы запускаете свой скрипт из командной строки, а каталог, содержащий ваш скрипт, является текущим рабочим каталогом (то есть вы использовали команду cd для перехода в каталог до запуска скрипта). Боги! Надеюсь, мне не нужно объяснять, почему это не сработает, если ваш скрипт Python находится в PATH где-то, и вы запустили его, просто набрав имя вашего файла сценария.
К счастью, есть волшебное заклинание, которое будет работать во всех случаях, которые я тестировал. К сожалению, магическое заклинание больше, чем просто строка или два кода.
import inspect
import os
import sys
# Add script directory to sys.path.
# This is complicated due to the fact that __file__ is not always defined.
def GetScriptDirectory():
if hasattr(GetScriptDirectory, "dir"):
return GetScriptDirectory.dir
module_path = ""
try:
# The easy way. Just use __file__.
# Unfortunately, __file__ is not available when cx_freeze is used or in IDLE.
module_path = __file__
except NameError:
if len(sys.argv) > 0 and len(sys.argv[0]) > 0 and os.path.isabs(sys.argv[0]):
module_path = sys.argv[0]
else:
module_path = os.path.abspath(inspect.getfile(GetScriptDirectory))
if not os.path.exists(module_path):
# If cx_freeze is used the value of the module_path variable at this point is in the following format.
# {PathToExeFile}\{NameOfPythonSourceFile}. This makes it necessary to strip off the file name to get the correct
# path.
module_path = os.path.dirname(module_path)
GetScriptDirectory.dir = os.path.dirname(module_path)
return GetScriptDirectory.dir
sys.path.append(os.path.join(GetScriptDirectory(), "lib"))
print(GetScriptDirectory())
print(sys.path)
Как вы можете видеть, это непростая задача!