Как я могу получить путь и имя файла, который выполняется в настоящее время?


482

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

Например, допустим, у меня есть три файла. Использование execfile :

  • script_1.pyзвонки script_2.py.
  • В свою очередь script_2.pyзвонки script_3.py.

Как я могу получить имя файла и путь script_3.py, из кода внутриscript_3.py , без необходимости передавать эту информацию в качестве аргументов script_2.py?

(Выполнение os.getcwd()возвращает исходный путь к файлу исходного сценария, а не текущий файл.)



2
os.path.realpath ( файл )
Гириш Гупта

Ответы:


256

p1.py:

execfile("p2.py")

p2.py:

import inspect, os
print (inspect.getfile(inspect.currentframe()) # script filename (usually with path)
print (os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))) # script directory

11
ВНИМАНИЕ: этот вызов не дает одинакового результата в разных средах. Рассмотрим принимая ответ Усаги ниже: stackoverflow.com/a/6628348/851398
Фарадея

3
@faraday: не могли бы вы привести пример? Я ответил на аналогичный вопрос с помощью,inspect.getabsfile() и он работал для всех случаев, которые я пытался.
JFS

1
Действительно ли ответ @Usagi лучше?
Дрор

4
Нах user13993 прибил его гораздо лучше
osirisgothra

6
user13993 действительно сделал это. Должно бытьos.path.realpath(__file__)
учуугака

566
__file__

как говорили другие. Вы также можете использовать os.path.realpath для удаления символических ссылок:

import os

os.path.realpath(__file__)

14
С этим подходом нужно быть осторожным, потому что иногда он __file__возвращает «script_name.py», а иногда «script_name.pyc». Таким образом, вывод не является стабильным.
мехатронер

27
Но поскольку мы используем только путь к этому файлу, это не имеет значения.
Уве Колоска

5
это странно: при запуске из командной строки "__file__"в кавычках (в виде строки) выдает dir, из которого запускается cmd, но __file__ (без кавычек - путь к исходному файлу ... почему это так
мюон

7
@muon не проверяется, существует ли переданная строка имени файла, и так как пути к файлам относятся к cwd, то есть то, что os.path.realpathфункция принимает за dirчасть пути. os.path.dirname(os.path.realpath(__file__))возвращает каталог с файлом. os.path.dirname(os.path.realpath("__file__"))возвращает cwd. os.path.dirname(os.path.realpath("here_be_dragons"))также возвращает CWD.
Джейми Булл,

86

Обновление 2018-11-28:

Вот краткое изложение экспериментов с Python 2 и 3. С

main.py - запускает foo.py
foo.py - запускает lib / bar.py
lib / bar.py - печатает выражения filepath

| Python | Run statement       | Filepath expression                    |
|--------+---------------------+----------------------------------------|
|      2 | execfile            | os.path.abspath(inspect.stack()[0][1]) |
|      2 | from lib import bar | __file__                               |
|      3 | exec                | (wasn't able to obtain it)             |
|      3 | import lib.bar      | __file__                               |

Для Python 2 может быть понятнее переключиться на пакеты, которые можно использовать from lib import bar- просто добавьте пустые __init__.pyфайлы в две папки.

Для Python 3 execfileне существует - ближайшая альтернатива есть exec(open(<filename>).read()), хотя это влияет на кадры стека. Проще всего просто использовать import fooи import lib.bar- __init__.pyфайлы не нужны.

Смотрите также Разница между import и execfile


Оригинальный ответ:

Вот эксперимент, основанный на ответах в этой теме - с Python 2.7.10 для Windows.

Основанные на стеке - единственные, которые, кажется, дают надежные результаты. Последние два имеют самый короткий синтаксис , то есть -

print os.path.abspath(inspect.stack()[0][1])                   # C:\filepaths\lib\bar.py
print os.path.dirname(os.path.abspath(inspect.stack()[0][1]))  # C:\filepaths\lib

Вот к ним добавляются sys как функции! Кредит @Usagi и @pablog

На основе следующих трех файлов и запуска main.py из его папки с python main.py(также пробовал execfiles с абсолютными путями и вызовами из отдельной папки).

C: \ filepaths \ main.py: execfile('foo.py')
C: \ filepaths \ foo.py: execfile('lib/bar.py')
C: \ filepaths \ lib \ bar.py:

import sys
import os
import inspect

print "Python " + sys.version
print

print __file__                                        # main.py
print sys.argv[0]                                     # main.py
print inspect.stack()[0][1]                           # lib/bar.py
print sys.path[0]                                     # C:\filepaths
print

print os.path.realpath(__file__)                      # C:\filepaths\main.py
print os.path.abspath(__file__)                       # C:\filepaths\main.py
print os.path.basename(__file__)                      # main.py
print os.path.basename(os.path.realpath(sys.argv[0])) # main.py
print

print sys.path[0]                                     # C:\filepaths
print os.path.abspath(os.path.split(sys.argv[0])[0])  # C:\filepaths
print os.path.dirname(os.path.abspath(__file__))      # C:\filepaths
print os.path.dirname(os.path.realpath(sys.argv[0]))  # C:\filepaths
print os.path.dirname(__file__)                       # (empty string)
print

print inspect.getfile(inspect.currentframe())         # lib/bar.py

print os.path.abspath(inspect.getfile(inspect.currentframe())) # C:\filepaths\lib\bar.py
print os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) # C:\filepaths\lib
print

print os.path.abspath(inspect.stack()[0][1])          # C:\filepaths\lib\bar.py
print os.path.dirname(os.path.abspath(inspect.stack()[0][1]))  # C:\filepaths\lib
print

72

Я думаю, что это чище

import inspect
print inspect.stack()[0][1]

и получает ту же информацию, что и:

print inspect.getfile(inspect.currentframe())

Где [0] - текущий кадр в стеке (вершина стека), а [1] - для имени файла, увеличьте, чтобы вернуться в стек, т.е.

print inspect.stack()[1][1]

будет именем файла скрипта, который вызвал текущий кадр. Кроме того, использование [-1] приведет вас к нижней части стека, к исходному скрипту вызова.


4
Не рекомендуется полагаться на положение внутри кортежа. Совершенно не ясно, какие данные вы пытаетесь получить при чтении кода.
jpmc26

5
inspect.getfile()возвращает __file__атрибут, если передан объект модуля. inspect.currentframe()возвращает модуль. Ergo, это дорогой способ сказать __file__.
Мартин Питерс

inspect.stack()это довольно дорогая функция, более чем просто inspect.currentframe(), и она тоже вызывает inspect.getfile()объект модуля.
Мартин Питерс

42
import os
os.path.dirname(__file__) # relative directory path
os.path.abspath(__file__) # absolute file path
os.path.basename(__file__) # the file name only

1
Я только что попробовал комментарий @Pat Notz. Я думаю, что вы могли бы просто получить имя файла до конца __file__.
hlin117

В Python3, os.path.dirnameдаст вам относительный путь, откуда вы запускаете скрипт. например , в будет и не абсолютный путь к сценарию. Я искал abspath, но удаляю имя скрипта. Первый элемент sys.path, по-видимому, является ответом . python ../../test.pyos.path.dirname../../sys.path[0]
Аериман

37

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

Если вы хотите узнать имя исполняемого файла (то есть корневого файла, переданного интерпретатору python для текущей программы) из файла, который может быть импортирован как модуль, вам нужно сделать это (предположим, это в файле с именем foo.py ):

import inspect

print inspect.stack()[-1][1]

Потому что последнее, что ( [-1]) в стеке - это первое, что вошло в него (стеки - это структуры данных LIFO / FILO).

Затем в файле bar.py, если вы import fooбудете печатать bar.py , а не foo.py , который будет значением всех этих:

  • __file__
  • inspect.getfile(inspect.currentframe())
  • inspect.stack()[0][1]

Это работает хорошо, но не для модульного теста на затмение, я получил /home/user/Softwares/eclipse/plugins/org.python.pydev_4.5.5.201603221110/pysrc
hayj

2
Это sys.modules['__main__'].__file__действительно дорогой способ написания .
Мартин Питерс

14
import os
print os.path.basename(__file__)

это даст нам только имя файла. т.е. если abspath файла c: \ abcd \ abc.py, то во 2-й строке будет напечатано abc.py


14

Не совсем понятно, что вы подразумеваете под «путем к файлу файла, который в данный момент выполняется в процессе». sys.argv[0]обычно содержит местоположение скрипта, который был вызван интерпретатором Python. Проверить документации sys для более подробной информации.

Как указали @Tim и @Pat Notz, атрибут __file__ обеспечивает доступ к

файл, из которого был загружен модуль, если он был загружен из файла


1
«print os.path.abspath ( file )» и «print inspect.getfile (inspect.currentframe ())» не работают, когда мы передаем программу python в win32 exe. Работает только sys.argv [0]! :) но вы получите только имя!
А.Ф.

11

У меня есть скрипт, который должен работать в среде Windows. С этим фрагментом кода я закончил:

import os,sys
PROJECT_PATH = os.path.abspath(os.path.split(sys.argv[0])[0])

это довольно хакерское решение. Но это не требует никаких внешних библиотек, и это самое главное в моем случае.


1
Для этого мне пришлось «импортировать os, sys», но пока это лучший ответ, который на самом деле возвращает только путь без имени файла в конце строки.
Эммаграс


8
import os
os.path.dirname(os.path.abspath(__file__))

Нет необходимости проверять или любую другую библиотеку.

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


Это не даст желаемого ответа, если текущий рабочий каталог (os.getcwd) отличается от каталога, в котором находится файл.
Железная подушка

2
Как же так? У меня отлично работает в этом случае. Я получаю каталог, в котором находится файл.
Майкл Миор

@IronPillow, возможно, этот ответ поможет вам с тем, что вам нужно. stackoverflow.com/a/41546830/3123191
Kwuite,


6
import sys

print sys.path[0]

это напечатало бы путь выполняемого в данный момент скрипта


2
sys.path [0] очень полезен, но дает путь к script1, а не к script3, как было запрошено
James

По крайней мере, в OS X с 2.7 я не считаю, что это делает что-то надежное. Это работает, если выполняется непосредственно тот же файл. Не работает из repl, особенно из импортированного яйца
uchuugaka


4

Ты можешь использовать inspect.stack()

import inspect,os
inspect.stack()[0]  => (<frame object at 0x00AC2AC0>, 'g:\\Python\\Test\\_GetCurrentProgram.py', 15, '<module>', ['print inspect.stack()[0]\n'], 0)
os.path.abspath (inspect.stack()[0][1]) => 'g:\\Python\\Test\\_GetCurrentProgram.py'

4

Поскольку Python 3 является довольно распространенным, я хотел включить pathlibответ, так как считаю, что сейчас он, вероятно, является лучшим инструментом для доступа к информации о файлах и путях.

from pathlib import Path

current_file: Path = Path(__file__).resolve()

Если вы ищете каталог текущего файла, это так же просто, как добавить .parentв Path()оператор:

current_path: Path = Path(__file__).parent.resolve()

3
import sys
print sys.argv[0]

10
К сожалению, это работает только в том случае, если скрипт был вызван с полным путем, потому что он возвращает только «первый аргумент» в командной строке, который является вызовом скрипта.
Cregox

2

Это должно работать:

import os,sys
filename=os.path.basename(os.path.realpath(sys.argv[0]))
dirname=os.path.dirname(os.path.realpath(sys.argv[0]))

2
print(__file__)
print(__import__("pathlib").Path(__file__).parent)

4
Код только ответы не рекомендуется. Пожалуйста, добавьте некоторые объяснения относительно того, как это решает проблему, или как это отличается от существующих ответов. Из обзора
Ник

1

Получить каталог исполняемого скрипта

 print os.path.dirname( inspect.getfile(inspect.currentframe()))

1

Я всегда использовал функцию os текущего рабочего каталога или CWD. Это часть стандартной библиотеки, и ее очень легко реализовать. Вот пример:

    import os
    base_directory = os.getcwd()

1
Не могли бы вы изменить свой ответ так, чтобы он относился к поставленному вопросу? Этот ответ не относится к вопросу «Как мне получить путь и имя файла, который в данный момент выполняется? »
Марко

1
Это дает путь, откуда вы запустили команду python. Так что, похоже, это работает, когда вы запускаете python script.pyкоманду в той же папке, в которой вы уже находитесь, хотя в действительности она такая же, как и pwdв Linux.
Джордж

0

Я использовал подход с __file__,
os.path.abspath(__file__)
но есть небольшой трюк, он возвращает файл .py при первом запуске кода, при следующих запусках дается имя файла * .pyc,
поэтому я остался с:
inspect.getfile(inspect.currentframe())
или
sys._getframe().f_code.co_filename


0

Я написал функцию, которая принимает во внимание отладчик затмения и unittest . Возвращает папку первого запускаемого вами скрипта. При желании вы можете указать переменную __file__ , но главное - вам не нужно совместно использовать эту переменную во всей иерархии вызовов .

Может быть, вы справитесь с другими сложными случаями, которых я не видел, но для меня это нормально.

import inspect, os
def getRootDirectory(_file_=None):
    """
    Get the directory of the root execution file
    Can help: http://stackoverflow.com/questions/50499/how-do-i-get-the-path-and-name-of-the-file-that-is-currently-executing
    For eclipse user with unittest or debugger, the function search for the correct folder in the stack
    You can pass __file__ (with 4 underscores) if you want the caller directory
    """
    # If we don't have the __file__ :
    if _file_ is None:
        # We get the last :
        rootFile = inspect.stack()[-1][1]
        folder = os.path.abspath(rootFile)
        # If we use unittest :
        if ("/pysrc" in folder) & ("org.python.pydev" in folder):
            previous = None
            # We search from left to right the case.py :
            for el in inspect.stack():
                currentFile = os.path.abspath(el[1])
                if ("unittest/case.py" in currentFile) | ("org.python.pydev" in currentFile):
                    break
                previous = currentFile
            folder = previous
        # We return the folder :
        return os.path.dirname(folder)
    else:
        # We return the folder according to specified __file__ :
        return os.path.dirname(os.path.realpath(_file_))

0

Чтобы сохранить согласованность миграции между платформами (macOS / Windows / Linux), попробуйте:

path = r'%s' % os.getcwd().replace('\\','/')


2
Это не верно. Вы получите текущий путь, но не путь к текущему файлу.
Чарльз Плагер

0

Самый простой способ это:

в script_1.py:

import subprocess
subprocess.call(['python3',<path_to_script_2.py>])

в script_2.py:

sys.argv[0]

PS: я пытался execfile, но так как он читает script_2.py в виде строки, sys.argv[0]вернулся <string>.


0

Вот то, что я использую, чтобы я мог бросить свой код в любом месте без проблем. __name__всегда определяется, но __file__определяется только тогда, когда код запускается как файл (например, не в IDLE / iPython).

    if '__file__' in globals():
        self_name = globals()['__file__']
    elif '__file__' in locals():
        self_name = locals()['__file__']
    else:
        self_name = __name__

В качестве альтернативы это может быть записано как:

self_name = globals().get('__file__', locals().get('__file__', __name__))

-2

Большинство из этих ответов были написаны на Python версии 2.x или более ранней. В Python 3.x синтаксис для функции печати изменился и теперь требует скобок, то есть print ().

Итак, этот более ранний ответ от user13993 в Python 2.x:

import inspect, os
print inspect.getfile(inspect.currentframe()) # script filename (usually with path)
print os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) # script directory

Становится в Python 3.x:

import inspect, os
print(inspect.getfile(inspect.currentframe())) # script filename (usually with path)
print(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) ) # script directory

-3

если вы хотите просто имя файла без, ./или .pyвы можете попробовать это

filename = testscript.py
file_name = __file__[2:-3]

file_name напечатает тестовый скрипт, который вы можете сгенерировать как угодно, изменив индекс внутри []


-3
import os

import wx


# return the full path of this file
print(os.getcwd())

icon = wx.Icon(os.getcwd() + '/img/image.png', wx.BITMAP_TYPE_PNG, 16, 16)

# put the icon on the frame
self.SetIcon(icon)

7
os.getcwd () возвращает текущий РАБОЧИЙ каталог PROCESS, а не каталог текущего исполняемого файла. Может показаться, что он возвращает правильные результаты, но во многих случаях результат не будет родительским каталогом текущего файла. Намного лучше использовать os.path.dirname ( файл ), как предложено выше.
samaspin
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.