Как получить путь к текущему исполняемому файлу в Python?
Это может показаться вопросом новичка, но это не так. Некоторые общие подходы не работают во всех случаях:
sys.argv [0]
Это означает использование path = os.path.abspath(os.path.dirname(sys.argv[0]))
, но это не работает, если вы работаете из другого скрипта Python в другом каталоге, и это может случиться в реальной жизни.
__файл__
Это означает использование path = os.path.abspath(os.path.dirname(__file__))
, но я обнаружил, что это не работает:
py2exe
не имеет__file__
атрибут, но есть обходной путь- Когда вы бежите из IDLE с
execute()
здесь нет__file__
атрибут - OS X 10.6, где я получаю
NameError: global name '__file__' is not defined
Связанные вопросы с неполными ответами:
- Python - Найти путь к файлу, который выполняется
- Путь к текущему файлу зависит от того, как я выполняю программу
- Как узнать путь запуска скрипта в Python?
- Изменить каталог на каталог скрипта Python
Я ищу общее решение, которое будет работать во всех вышеупомянутых случаях использования.
Обновить
Вот результат теста:
Вывод python a.py (в Windows)
a.py: __file__= a.py
a.py: os.getcwd()= C:\zzz
b.py: sys.argv[0]= a.py
b.py: __file__= a.py
b.py: os.getcwd()= C:\zzz
a.py
#! /usr/bin/env python
import os, sys
print "a.py: sys.argv[0]=", sys.argv[0]
print "a.py: __file__=", __file__
print "a.py: os.getcwd()=", os.getcwd()
print
execfile("subdir/b.py")
подкаталог /b.py
#! /usr/bin/env python
import os, sys
print "b.py: sys.argv[0]=", sys.argv[0]
print "b.py: __file__=", __file__
print "b.py: os.getcwd()=", os.getcwd()
print
дерево
C:.
| a.py
\---subdir
b.py
11 ответов
Вы не можете напрямую определить местоположение основного скрипта, который выполняется. В конце концов, иногда сценарий вообще не приходит из файла. Например, он может исходить от интерактивного интерпретатора или динамически генерируемого кода, хранящегося только в памяти.
Однако вы можете надежно определить местоположение модуля, поскольку модули всегда загружаются из файла. Если вы создаете модуль со следующим кодом и помещаете его в ту же директорию, что и ваш основной скрипт, тогда основной скрипт может импортировать модуль и использовать его для поиска себя.
some_path / module_locator.py:
def we_are_frozen():
# All of the modules are built-in to the interpreter, e.g., by py2exe
return hasattr(sys, "frozen")
def module_path():
encoding = sys.getfilesystemencoding()
if we_are_frozen():
return os.path.dirname(unicode(sys.executable, encoding))
return os.path.dirname(unicode(__file__, encoding))
some_path / main.py:
import module_locator
my_path = module_locator.module_path()
Если у вас есть несколько основных сценариев в разных каталогах, вам может потребоваться более одной копии module_locator.
Конечно, если ваш основной сценарий загружен каким-либо другим инструментом, который не позволяет импортировать модули, которые находятся рядом с вашим сценарием, то вам не повезло. В таких случаях информация, которую вы ищете, просто не существует нигде в вашей программе. Лучше всего подать сообщение об ошибке авторам инструмента.
Во-первых, вам нужно импортировать из inspect
а также os
from inspect import getsourcefile
from os.path import abspath
Далее, где вы хотите найти исходный файл, вы просто используете
abspath(getsourcefile(lambda:0))
Это решение является надежным даже в исполняемых файлах
import inspect, os.path
filename = inspect.getframeinfo(inspect.currentframe()).filename
path = os.path.dirname(os.path.abspath(filename))
Я столкнулся с подобной проблемой, и я думаю, что это может решить проблему:
def module_path(local_function):
''' returns the module path without the use of __file__. Requires a function defined
locally in the module.
from http://stackru.com/questions/729583/getting-file-path-of-imported-module'''
return os.path.abspath(inspect.getsourcefile(local_function))
Это работает для обычных скриптов и в режиме ожидания. Все, что я могу сказать, это попробовать это для других!
Мое типичное использование:
from toolbox import module_path
def main():
pass # Do stuff
global __modpath__
__modpath__ = module_path(main)
Теперь я использую __modpath__ вместо __file__.
Вы просто позвонили:
path = os.path.abspath(os.path.dirname(sys.argv[0]))
вместо:
path = os.path.dirname(os.path.abspath(sys.argv[0]))
abspath()
дает вам абсолютный путь sys.argv[0]
(имя вашего кода) и dirname()
возвращает путь к каталогу без имени файла.
Короткий ответ: нет гарантированного способа получить нужную информацию, однако есть эвристики, которые работают практически всегда на практике. Вы можете посмотреть, как найти расположение исполняемого файла в C?, В нем обсуждается проблема с точки зрения Си, но предложенные решения легко транскрибируются в Python.
См. Мой ответ на вопрос " Импорт модулей из родительской папки" для получения соответствующей информации, в том числе почему мой ответ не использует ненадежных __file__
переменная. Это простое решение должно быть совместимо с различными операционными системами в качестве модулей os
а также inspect
прийти как часть Python.
Во-первых, вам нужно импортировать части модулей inspect и os.
from inspect import getsourcefile
from os.path import abspath
Затем используйте следующую строку в любом другом месте, где это необходимо в вашем коде Python:
abspath(getsourcefile(lambda:0))
Как это устроено:
Из встроенного модуля os
(описание ниже), abspath
Инструмент импортирован.
Подпрограммы ОС для Mac, NT или Posix в зависимости от того, на какой системе мы работаем.
затем getsourcefile
(описание ниже) импортируется из встроенного модуля inspect
,
Получите полезную информацию от живых объектов Python.
abspath(path)
возвращает абсолютную / полную версию пути к файлуgetsourcefile(lambda:0)
каким-то образом получает внутренний исходный файл объекта функции лямбда, поэтому возвращает'<pyshell#nn>'
в оболочке Python или возвращает путь к файлу кода Python, выполняемого в данный момент.
С помощью abspath
на результат getsourcefile(lambda:0)
следует убедиться, что сгенерированный путь к файлу является полным путем к файлу Python.
Это объясненное решение изначально было основано на коде из ответа в разделе Как получить путь к текущему исполняемому файлу в Python?,
Это должно сделать кросс-платформенное решение (если вы не используете интерпретатор или что-то в этом роде):
import os, sys
non_symbolic=os.path.realpath(sys.argv[0])
program_filepath=os.path.join(sys.path[0], os.path.basename(non_symbolic))
sys.path[0]
каталог, в котором находится ваш вызывающий скрипт (в первую очередь он ищет модули, которые будут использоваться этим скриптом). Мы можем взять имя файла самого конца sys.argv[0]
(что я и сделал с os.path.basename
). os.path.join
просто склеивает их кросс-платформенным способом. os.path.realpath
просто удостоверимся, что если мы получим какие-либо символические ссылки с именами, отличными от самого скрипта, мы получим настоящее имя скрипта
У меня нет Mac; Итак, я не проверял это на одном. Пожалуйста, дайте мне знать, если это работает, как кажется, должно. Я проверил это в Linux (Xubuntu) с Python 3.4. Обратите внимание, что многие решения этой проблемы не работают на Mac (так как я слышал, что __file__
нет на Маках).
Обратите внимание, что если ваш скрипт является символической ссылкой, он даст вам путь к файлу, на который он ссылается (а не путь к символической ссылке).
Ты можешь использовать Path
от pathlib
модуль:
from pathlib import Path
# ...
Path(__file__)
Вы можете использовать звонок для parent
идти дальше по пути:
Path(__file__).parent
Просто добавьте следующее:
from sys import *
path_to_current_file = sys.argv[0]
print(path_to_current_file)
Или же:
from sys import *
print(sys.argv[0])
Мое решение:
import os
print(os.path.join(os.getcwd(), __file__))
Если код исходит из файла, вы можете получить его полное имя
sys._getframe().f_code.co_filename
Вы также можете получить имя функции как f_code.co_name
import os
current_file_path=os.path.dirname(os.path.realpath('__file__'))