Отримайте ім'я поточного сценарію в Python


407

Я намагаюся отримати назву сценарію Python, який зараз працює.

У мене є сценарій, який називається, foo.pyі я хотів би зробити щось подібне, щоб отримати ім'я сценарію:

print Scriptname

Відповіді:


620

Ви можете використовувати __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для цього потрібно працювати. Я додав би це у відповідь.
Nick Chammas

14
@ cdunn2001: import osі import os.pathє абсолютно рівнозначними.
Свен Марнах

2
@ sven-marnach: О, ти маєш рацію . Я роблю це неправильно роками!
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, тому що це (a) трохи акуратніше і (b) все ще буде працювати в модулі (де змінною файлу буде файл модуля, а не виконаний).
Роберт

Ця відповідь хороша тим, що вона працює і в 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(...)на це 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, тому використовуйте синтаксис імпорту як вище, щоб зробити його портативним.


Це працює в багатьох випадках, але не тоді, коли я використовую 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: ім'я "Шлях" не визначено
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


1
sys.argv [0] [: - 3] зробив би
kon psych

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



0

всі відповіді чудові, але є деякі проблеми, які ви можете не побачити з першого погляду.

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

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

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

моя бібліотека bitranox / lib_programname в github робить саме це:

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

тим шляхом, моє рішення працює до сих пір з setup.py test, uwsgi, pytest, pycharm pytest, pycharm docrunner (doctest), dreampie,eclipse

також є приємна стаття в блозі про цю проблему від Тіста Хеллмана, "Визначення імені процесу з Python"


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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.