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

408

Я пытаюсь получить имя скрипта Python, который в данный момент выполняется.

У меня есть сценарий, foo.pyи я хотел бы сделать что-то вроде этого, чтобы получить имя сценария:

print Scriptname
SubniC
источник

Ответы:

621

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

Если вы хотите опустить часть каталога (которая может присутствовать), вы можете использовать os.path.basename(__file__).

Свен Марнах
источник
15
Python 3.2: " Exception NameError: NameError("global name '__file__' is not defined",)"
sdaau
20
@sdaau: __file__не определено в интерактивном переводчике, потому что это бессмысленно. Он устанавливается реализацией импорта, поэтому, если вы используете нестандартный механизм импорта, он также может быть не установлен.
Свен Марнач
8
По крайней мере, для Python 2.7, я считаю, что import osэто необходимо для работы. Я бы добавил это в ответ.
Ник Чаммас
14
@ cdunn2001: import osи import os.pathполностью эквивалентны.
Свен Марнач
2
@ Свен-Марнах: О, ты прав . Я делал это неправильно годами!
cdunn2001
136
import sys
print sys.argv[0]

Это будет печатать foo.pyдля python foo.py, dir/foo.pyдля python dir/foo.pyи т. Д. Это первый аргумент для python. (Обратите внимание, что после py2exe это будет foo.exe.)

Крис Морган
источник
33
@DenisMalinovsky: определить "не будет работать". Если вы позвоните python linkfile.py, где linkfile.pyнаходится символическая ссылка realfile.py, sys.argv[0]будет 'linkfile.py', что может или не может быть то, что вы хотите; это конечно то, чего я ожидаю . __file__то же самое: будет linkfile.py. Если вы хотите найти 'realfile.py'с 'linkfile.py', попробуйте os.path.realpath('linkfile.py').
Крис Морган
6
+1, потому что (а) немного аккуратнее и (б) все равно будет работать в модуле (где файловая переменная будет файлом модуля, а не исполняемым).
Роберт
Этот ответ хорош, потому что он работает и в IDLE. В качестве примечания, чтобы получить только имя файла, вы можете написать os.path.basename (sys.argv [0])
Стивен Блюен,
Что еще более важно, это не работает, кроме как из основного файла. Не используйте это, используйте __file__вместо этого.
Аполлис поддерживает Монику
ЧТО!!! Вы даже пробовали это? Точно противоположное верно. Спрашивающий спросил имя запущенного скрипта python, а не файл python, который в данный момент выполняется. Представьте, что у вас есть сценарий, который при возникновении ошибки выводит имя сценария вместе с разрешенными аргументами. Вы помещаете это в функцию, используя один из этих двух методов. В какой-то момент вы решаете перенести функцию во внешнюю библиотеку. Вы хотите напечатать имя основного скрипта или имя файла библиотеки, который выполняется?
Джон Дейган
71

Для полноты картины я подумал, что было бы целесообразно обобщить различные возможные результаты и предоставить ссылки для точного поведения каждого из них:

  • __file__является текущим исполняемым файлом, как указано в официальной документации :

    __file__путь к файлу, из которого был загружен модуль, если он был загружен из файла. __file__Атрибут может отсутствовать для некоторых типов модулей, таких как C модули , которые статически связаны в интерпретатор; для модулей расширения, загружаемых динамически из общей библиотеки, это путь к файлу общей библиотеки.

    С Python3.4 годом, на вопрос 18416 , __file__всегда абсолютный путь, если в данный момент выполняет файл не является сценарием , который был выполнен непосредственно (не через переводчик с -mпараметром командной строки) , используя относительный путь.

  • __main__.__file__(требует импорта __main__) просто обращается к вышеупомянутому __file__атрибуту основного модуля , например, сценария, который был вызван из командной строки.

  • sys.argv[0](требует импорта sys) - это имя сценария, которое было вызвано из командной строки и может быть абсолютным путем, как подробно описано в официальной документации :

    argv[0]имя скрипта (зависит от операционной системы, является ли это полным путем или нет). Если команда была выполнена с использованием параметра -cкомандной строки для интерпретатора, argv[0]устанавливается строка '-c'. Если имя интерпретатора не было передано интерпретатору Python, argv[0]это пустая строка.

    Как упоминалось в другом ответе на этот вопрос , скрипты Python, которые были преобразованы в автономные исполняемые программы с помощью таких инструментов, как py2exe или PyInstaller, могут не отображать желаемый результат при использовании этого подхода (то есть sys.argv[0]будут содержать имя исполняемого файла, а не имя основного файла Python в этом исполняемом файле).

  • Если ни одна из вышеупомянутых опций не работает, возможно, из-за нерегулярной операции импорта, модуль проверки может оказаться полезным. В частности, вызов inspect.getfile(...)on inspect.currentframe()может работать, хотя последний будет возвращатьсяNone при запуске в реализации без фрейма стека Python .


Обработка символических ссылок

Если текущий скрипт является символической ссылкой, то все вышеперечисленное будет возвращать путь символической ссылки, а не путь к реальному файлу, и его os.path.realpath(...)следует вызывать для извлечения последней.


Дальнейшие манипуляции, которые извлекают фактическое имя файла

os.path.basename(...)может быть вызван по любому из вышеперечисленных для извлечения фактического имени файла и os.path.splitext(...)может быть вызван по фактическому имени файла для усечения его суффикса, как в os.path.splitext(os.path.basename(...)).

Из Python 3.4 и далее, за PEP 428 , то PurePathкласс из pathlibмодуля может быть также использован на любом из указанных выше. В частности, pathlib.PurePath(...).nameизвлекает фактическое имя файла и pathlib.PurePath(...).stemизвлекает фактическое имя файла без его суффикса.

Йоэль
источник
66

Обратите внимание, что __file__это даст файл, в котором находится этот код, который можно импортировать и отличать от интерпретируемого основного файла. Чтобы получить основной файл, можно использовать специальный модуль __main__ :

import __main__ as main
print(main.__file__)

Обратите внимание, что это __main__.__file__работает в Python 2.7, но не в 3.2, поэтому используйте синтаксис import-as, как описано выше, чтобы сделать его переносимым.

Амброз Бижак
источник
Это работает во многих случаях, но не когда я использую rPythonпакет из Rязыка. Это, должно быть, исключительный случай, с которым слишком трудно разобраться.
Леонид
Действительно, в пакет rPython встроен интерпретатор python, что означает, что нет «основного» файла, как это бывает, когда python работает сам по себе (вы обнаружите, что такое же поведение происходит при каждом внедрении python). Он импортирует __main__изнутри, для использования при передаче переменных между Rи python, поэтому было бы относительно легко установить его __main__.__file__перед вызовом чего-либо еще, но я даже не уверен, что будет подходящим значением в этом случае.
Перкинс
42

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

import sys    
import os    
file_name =  os.path.basename(sys.argv[0])
Манодж Саху
источник
1
Мне также нравится отделять расширение, поэтому я использую: os.path.splitext (os.path.basename (sys.argv [0])) [0]
RufusVS
19

Для современных версий Python (3.4+), Path(__file__).nameдолжно быть более идиоматичным. Кроме того, Path(__file__).stemдает вам имя сценария без .pyрасширения.

Эмиль Мельников
источник
NameError: имя 'Path' не определено
RufusVS
5
Вы должны from pathlib import Pathсначала.
Эмиль Мельников
«современный» означает Python 3.x?
einpoklum
1
@einpoklum pathlibбыл введен в Python 3.4, поэтому он должен работать, начиная с Python 3.4.
Андрей Семакин
9

Примечание. Если вы используете Python 3+, вам следует использовать вместо этого функцию print ()

Предполагая, что имя файла foo.py, приведенный ниже фрагмент

import sys
print sys.argv[0][:-3]

или

import sys
print sys.argv[0][::-1][3:][::-1]

Что касается других расширений с большим количеством символов, например имя файла foo.pypy

import sys
print sys.argv[0].split('.')[0]

Если вы хотите извлечь из абсолютного пути

import sys
print sys.argv[0].split('/')[-1].split('.')[0]

будет выводить foo

xtonousou
источник
1
sys.argv [0] [: - 3] сделает
kon
@konpsych, это более элегантно
xtonousou
Существует большая разница между __file__и sys.argv[0], см. Stackoverflow.com/questions/5851588/…
Максим Ганенко
8

Первым аргументом в sys будет текущее имя файла, так что это будет работать

   import sys
   print sys.argv[0] # will print the file name
Чарли Оконор
источник
7

Если вы делаете необычный импорт (например, это файл опций), попробуйте:

import inspect
print (inspect.getfile(inspect.currentframe()))

Обратите внимание, что это вернет абсолютный путь к файлу.

Гаджендра Д Амби
источник
3

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

import os

script_name = os.path.splitext(os.path.basename(__file__))[0]
Кришн Сингх
источник
2

Так как ОП запросил имя текущего файла скрипта, я бы предпочел

import os
os.path.split(sys.argv[0])[1]
PeterXX
источник
1

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

давайте определим, что мы хотим - нам нужно имя сценария, который был выполнен, а не имя текущего модуля - поэтому __file__будет работать, только если он используется в исполняемом сценарии, а не в импортированном модуле. sys.argvТакже сомнительно - что если ваша программа была вызвана pytest? или бегун-пидок? или если он был назван uwsgi?

и - есть третий способ получения имени сценария, который я не видел в ответах - Вы можете проверить стек.

Другая проблема заключается в том, что Вы (или какая-либо другая программа) можете вмешиваться sys.argvи __main__.__file__- это может присутствовать, а может и не быть. Это может быть действительным или нет. По крайней мере, вы можете проверить, существует ли сценарий (желаемый результат)!

моя библиотека bitranox / lib_programname в github делает именно это:

  • проверьте, __main__присутствует ли
  • проверьте, __main__.__file__присутствует ли
  • дает __main__.__file__действительный результат (этот сценарий существует?)
  • если нет: проверьте sys.argv:
  • есть ли в sys.argv pytest, docrunner и т. д.? -> если да, игнорируй это
  • мы можем получить действительный результат здесь?
  • если нет: проверьте стек и, возможно, получите оттуда результат
  • если стек также не дает действительного результата, тогда выдается исключение.

тем путем, мое решение работает до сих пор с setup.py test, uwsgi, pytest, pycharm pytest, pycharm docrunner (doctest), dreampie,eclipse

есть также хорошая статья в блоге об этой проблеме от Dough Hellman, "Определение имени процесса из Python"

bitranox
источник
0

Мое быстрое грязное решение:

__file__.split('/')[-1:][0]
E.Big
источник
2
Лучше использовать os.pathдля разделения имен файлов
Максим Ганенко
0

Начиная с Python 3.5 вы можете просто:

from pathlib import Path
Path(__file__).stem

Подробнее здесь: https://docs.python.org/3.5/library/pathlib.html#pathlib.PurePath.stem

Например, у меня есть файл в моем пользовательском каталоге, названный test.pyтак:

from pathlib import Path

print(Path(__file__).stem)
print(__file__)

запустив эти выводы:

>>> python3.6 test.py
test
test.py
серебро
источник