Как мне получить путь к текущему исполняемому файлу в Python? - PullRequest
176 голосов
/ 13 апреля 2010

Это может показаться вопросом новичка, но это не так. Некоторые общие подходы работают не во всех случаях:

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 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

Ответы [ 13 ]

78 голосов
/ 13 апреля 2010

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

Однако вы можете надежно определить местоположение модуля, так как модули всегда загружаются из файла. Если вы создадите модуль со следующим кодом и поместите его в тот же каталог, что и ваш основной сценарий, то основной сценарий может импортировать модуль и использовать его для определения своего местоположения.

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.

Конечно, если ваш основной сценарий загружается каким-либо другим инструментом, который не позволяет импортировать модули, которые совмещены с вашим сценарием, вам не повезло. В таких случаях информация, которую вы ищете, просто не существует нигде в вашей программе. Лучше всего подать сообщение об ошибке авторам инструмента.

53 голосов
/ 28 августа 2013

Сначала вам нужно импортировать из inspect и os

from inspect import getsourcefile
from os.path import abspath

Далее, где бы вы ни хотели найти исходный файл, просто используйте

abspath(getsourcefile(lambda:0))
14 голосов
/ 21 апреля 2011

У меня была похожая проблема, и я думаю, что это может решить проблему:

def module_path(local_function):
   ''' returns the module path without the use of __file__.  Requires a function defined
   locally in the module.
   from http://stackoverflow.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 __.

10 голосов
/ 16 июня 2017

это решение устойчиво даже в исполняемых файлах

import inspect, os.path

filename = inspect.getframeinfo(inspect.currentframe()).filename
path     = os.path.dirname(os.path.abspath(filename))
6 голосов
/ 16 апреля 2010

Короткий ответ таков: не существует гарантированного способа получения необходимой информации , однако существуют эвристические методы, которые работают практически всегда на практике.Вы можете посмотреть на Как найти расположение исполняемого файла в C? .В нем обсуждается проблема с точки зрения Си, но предложенные решения легко транскрибируются в Python.

4 голосов
/ 04 ноября 2015

См. Мой ответ на вопрос Импорт модулей из родительской папки для получения соответствующей информации, включая информацию о том, почему в моем ответе не используется ненадежная переменная __file__. Это простое решение должно быть совместимо с различными операционными системами, так как модули os и inspect входят в состав Python.

Во-первых, вам необходимо импортировать части проверять и 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) каким-то образом получает внутренний исходный файл объекта функции lambda, поэтому возвращает '<pyshell#nn>' в оболочке Python или возвращает путь к файлу кода Python, выполняемого в данный момент.

Использование abspath в результате getsourcefile(lambda:0) должно гарантировать, что сгенерированный путь к файлу является полным путем к файлу Python.
Это объясненное решение изначально было основано на коде из ответа на Как мне получить путь к текущему исполняемому файлу в Python? .

3 голосов
/ 04 апреля 2018

Вы просто позвонили:

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() возвращает путь каталога без имени файла.

2 голосов
/ 10 октября 2016

Вы можете использовать Path из модуля pathlib:

from pathlib import Path

# ...

Path(__file__)

Вы можете использовать вызов parent, чтобы пойти дальше по пути:

Path(__file__).parent
2 голосов
/ 11 сентября 2014

Это должно сделать трюк кроссплатформенным способом (если вы не используете переводчик или что-то в этом роде):

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__ отсутствует на компьютерах Mac).

Обратите внимание, что если ваш скрипт является символической ссылкой, он даст вам путь к файлу, на который он ссылается (а не путь к символической ссылке).

1 голос
/ 25 октября 2018

Если код приходит из файла, вы можете получить его полное имя

sys._getframe().f_code.co_filename

Вы также можете получить имя функции как f_code.co_name

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...