Я хотел бы посмотреть, как лучше определить текущий каталог скриптов в python?
Я обнаружил, что из-за множества способов вызова кода на Python трудно найти хорошее решение.
Вот некоторые проблемы:
__file__
не определен , если скрипт выполняется сexec
,execfile
__module__
определяется только в модулях
Случаи использования:
./myfile.py
python myfile.py
./somedir/myfile.py
python somedir/myfile.py
execfile('myfile.py')
(из другого скрипта, который может находиться в другом каталоге и может иметь другой текущий каталог.
Я знаю, что не существует идеального решения, но я ищу лучший подход, который решает большинство случаев.
Наиболее часто используется такой подход, os.path.dirname(os.path.abspath(__file__))
но он действительно не работает, если вы выполняете скрипт из другого exec()
.
Предупреждение
Любое решение, которое использует текущую директорию, потерпит неудачу, это может отличаться в зависимости от того, как вызывается скрипт, или его можно изменить внутри запущенного скрипта.
python
pythonpath
dirname
Bogdan
источник
источник
pathlib
Решение Рона Каляна, если вы используете Python 3.4 или выше: stackoverflow.com/a/48931294/1011724python myfile.py
из оболочки это работает, но оба:!python %
и:!python myfile.py
изнутри vim терпят неудачу с системой не удается найти указанный путь. Это довольно раздражает. Кто-нибудь может прокомментировать причину этого и возможные обходные пути?Ответы:
это действительно лучшее, что вы собираетесь получить.
Необычно выполнять скрипт с
exec
/execfile
; обычно вы должны использовать инфраструктуру модуля для загрузки скриптов. Если вы должны использовать эти методы, я предлагаю установить__file__
вglobals
сценарии, который вы передаете, чтобы он мог прочитать это имя файла.Нет другого способа получить имя файла в исходном коде: как вы заметили, CWD может находиться в совершенно другом месте.
источник
Если вы действительно хотите охватить случай, через который вызывается скрипт
execfile(...)
, вы можете использоватьinspect
модуль для определения имени файла (включая путь). Насколько мне известно, это будет работать для всех перечисленных вами случаев:источник
chdir()
функцию до того, как она изменит результат. Также вызов скрипта python из другого каталога изменит результат, поэтому это не очень хорошее решение.os.path.expanduser("~")
это кроссплатформенный способ получить каталог пользователя. К сожалению, это не лучшая практика Windows для хранения данных приложения.chdir()
перед запуском скрипта; это дает правильный результат. Я попытался вызвать скрипт из другого каталога, и он также работает. Результаты такие же, как и наinspect.getabsfile()
основе решения .Работает на CPython, Jython, Pypy. Это работает, если скрипт выполняется с использованием
execfile()
(sys.argv[0]
и__file__
решения на основе-здесь потерпят неудачу). Это работает, если скрипт находится внутри исполняемого zip-файла (/ egg) . Работает, если скрипт «импортирован» (PYTHONPATH=/path/to/library.zip python -mscript_to_run
) из zip-файла; в этом случае он возвращает путь к архиву. Это работает, если скрипт скомпилирован в отдельный исполняемый файл (sys.frozen
). Это работает для символических ссылок (realpath
устраняет символические ссылки). Работает в интерактивном переводчике; в этом случае он возвращает текущий рабочий каталог.источник
getabsfile(..)
не упоминается в документации дляinspect
? Он появляется в источнике, связанном с этой страницей.getsourcefile()
,getfile()
которая задокументирована.В Python 3.4+ вы можете использовать более простой
pathlib
модуль:источник
Path(__file__)
(нет необходимости вinspect
модуле).Path(__file__)
выдаст,/path/to/script/currentscript.py
когда ОП захотел получить/path/to/script/
parent = Path(__file__).resolve().parent
Это намного приятнее..joinpath()
(или/
оператор) для этого, а не+
.os.path...
Подход был «сделать вещь» в Python 2.В Python 3 вы можете найти каталог скриптов следующим образом:
источник
Path(__file__).parent
. Ноcwd
это неправильно, это не текущий рабочий каталог , а каталог файла . Они могут быть одинаковыми, но обычно это не так.Просто используйте
os.path.dirname(os.path.abspath(__file__))
и очень внимательно изучите, существует ли реальная необходимость в том случае, когдаexec
используется. Это может быть признаком проблемного дизайна, если вы не можете использовать свой скрипт в качестве модуля.Имейте в виду Zen of Python # 8 , и если вы считаете, что есть хороший аргумент для варианта использования, для которого он должен работать
exec
, тогда, пожалуйста, сообщите нам более подробную информацию об истории проблемы.источник
Бы
делай что хочешь? Я не уверен, что именно вы подразумеваете под "текущим каталогом скриптов". Каким будет ожидаемый результат для приведенных вами вариантов использования?
источник
exec('myfile.py')
, так же, как__file__
иsys.argv[0]
.Во-первых ... пара пропущенных вариантов использования здесь, если мы говорим о способах внедрения анонимного кода ..
Но реальный вопрос в том, какова ваша цель - пытаетесь ли вы обеспечить какую-то безопасность? Или вы просто заинтересованы в том, что загружается.
Если вы заинтересованы в безопасности , имя файла, которое импортируется через exec / execfile, не имеет значения - вам следует использовать rexec , который предлагает следующее:
Однако, если это скорее академическое занятие ... вот пара глупых подходов, в которые вы, возможно, сможете углубиться ...
Примеры скриптов:
./deep.py
./deeper.py
/tmp/deepest.py
./codespy.py
Вывод
Конечно, это ресурсоемкий способ сделать это, вы бы отслеживали весь свой код ... Не очень эффективно. Но я думаю, что это новый подход, так как он продолжает работать, даже если вы углубляетесь в гнездо. Вы не можете переопределить 'Eval'. Хотя вы можете переопределить execfile ().
Обратите внимание, что этот подход требует только exec / execfile, а не import. Для перехвата нагрузки «модуль» более высокого уровня вы можете использовать sys.path_hooks ( Автор любезности PyMOTW).
Это все, что у меня есть на макушке.
источник
Вот частичное решение, все еще лучшее, чем все опубликованные.
Теперь это работает для всех вызовов, но если кто-то использует
chdir()
для изменения текущего каталога, это также не удастся.Ноты:
sys.argv[0]
не будет работать, вернется,-c
если вы выполните скрипт сpython -c "execfile('path-tester.py')"
источник
Это должно работать в большинстве случаев:
источник
Надеюсь, это поможет: - Если вы запустите скрипт / модуль из любого места, вы сможете получить доступ к
__file__
переменной, которая является переменной модуля, представляющей местоположение скрипта.С другой стороны, если вы используете интерпретатор, у вас нет доступа к этой переменной, где вы получите имя
NameError
иos.getcwd()
неверный каталог, если вы запускаете файл откуда-то еще.Это решение должно дать вам то, что вы ищете во всех случаях:
Я не проверил это полностью, но это решило мою проблему.
источник