Вопрос-Ответ

How do you properly determine the current script directory? [duplicate]

Как правильно определить текущий каталог скриптов?

Я хотел бы посмотреть, какой наилучший способ определить текущий каталог скриптов в 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().

Предупреждение

Любое решение, использующее текущий каталог, завершится сбоем, это может отличаться в зависимости от способа вызова скрипта или его можно изменить внутри запущенного скрипта.

Переведено автоматически
Ответ 1
os.path.dirname(os.path.abspath(__file__))

это действительно лучшее, что вы собираетесь получить.

Необычно выполнять скрипт с помощью exec/execfile; обычно вы должны использовать инфраструктуру модуля для загрузки скриптов. Если вам необходимо использовать эти методы, я предлагаю настроить __file__ вglobals, который вы передаете скрипту, чтобы он мог прочитать это имя файла.

Другого способа получить имя файла в исполняемом коде нет: как вы заметили, CWD может находиться в совершенно другом месте.

Ответ 2

Если вы действительно хотите описать случай, когда скрипт вызывается через execfile(...), вы можете использовать inspect модуль для вывода имени файла (включая путь). Насколько мне известно, это сработает для всех перечисленных вами случаев:

filename = inspect.getframeinfo(inspect.currentframe()).filename
path = os.path.dirname(os.path.abspath(filename))
Ответ 3

В Python 3.4+ вы можете использовать более простой pathlib модуль:

from inspect import currentframe, getframeinfo
from pathlib import Path

filename = getframeinfo(currentframe()).filename
parent = Path(filename).resolve().parent

Вы также можете использовать __file__ (когда это доступно), чтобы вообще избежать использования inspect модуля:

from pathlib import Path
parent = Path(__file__).resolve().parent
Ответ 4
#!/usr/bin/env python
import inspect
import os
import sys

def get_script_dir(follow_symlinks=True):
if getattr(sys, 'frozen', False): # py2exe, PyInstaller, cx_Freeze
path = os.path.abspath(sys.executable)
else:
path = inspect.getabsfile(get_script_dir)
if follow_symlinks:
path = os.path.realpath(path)
return os.path.dirname(path)

print(get_script_dir())

Это работает на CPython, Jython, Pypy. Это работает, если скрипт выполняется с использованием execfile() (решения на основе sys.argv[0] и __file__ здесь не сработают). Это работает, если скрипт находится внутри исполняемого zip-файла (/ egg). Это работает, если скрипт "импортирован" (PYTHONPATH=/path/to/library.zip python -mscript_to_run) из zip-файла; в этом случае он возвращает путь к архиву. Это работает, если скрипт скомпилирован в автономный исполняемый файл (sys.frozen). Это работает для символических ссылок (realpath устраняет символические ссылки). Это работает в интерактивном интерпретаторе; в этом случае он возвращает текущий рабочий каталог.

2023-09-08 15:30 python