Ruft den Namen des aktuellen Skripts in Python ab


407

Ich versuche, den Namen des Python-Skripts zu ermitteln, das gerade ausgeführt wird.

Ich habe ein Skript namens foo.pyund möchte so etwas tun, um den Skriptnamen zu erhalten:

print Scriptname

Antworten:


620

Sie können verwenden __file__, um den Namen der aktuellen Datei abzurufen. Bei Verwendung im Hauptmodul ist dies der Name des Skripts, das ursprünglich aufgerufen wurde.

Wenn Sie den Verzeichnisteil (der möglicherweise vorhanden ist) weglassen möchten, können Sie ihn verwenden os.path.basename(__file__).


15
Python 3.2: " Exception NameError: NameError("global name '__file__' is not defined",)"
sdaau

20
@sdaau: __file__ist im interaktiven Interpreter nicht definiert, da es dort bedeutungslos ist. Es wird von der Importimplementierung festgelegt. Wenn Sie also einen nicht standardmäßigen Importmechanismus verwenden, wird dieser möglicherweise auch nicht festgelegt.
Sven Marnach

8
Zumindest für Python 2.7 glaube ich, dass ein import oserforderlich ist, damit dies funktioniert. Ich würde dies in die Antwort aufnehmen.
Nick Chammas

14
@ cdunn2001: import osund import os.pathsind völlig gleichwertig.
Sven Marnach

2
@ sven-marnach: Oh, du hast recht . Ich mache es seit Jahren falsch!
cdunn2001

136
import sys
print sys.argv[0]

Dies wird foo.pyfür python foo.py, dir/foo.pyfür python dir/foo.pyusw. gedruckt . Es ist das erste Argument dafür python. (Beachten Sie, dass es nach py2exe sein würde foo.exe.)


33
@DenisMalinovsky: Definiere "wird nicht funktionieren". Wenn Sie anrufen python linkfile.py, wo linkfile.pyist ein Symlink zu realfile.py, sys.argv[0]wird 'linkfile.py', was kann oder kann nicht sein, was Sie wollen; es ist sicherlich das, was ich erwarte . __file__ist das gleiche: es wird sein linkfile.py. Wenn Sie wissen wollen , 'realfile.py'aus 'linkfile.py', versuchen os.path.realpath('linkfile.py').
Chris Morgan

6
1 , weil es (a) ein wenig saubere und (b) wird noch Arbeit in Modul (wo die Dateigröße die Moduldatei wäre, nicht die ausgeführt eins).
Robert

Diese Antwort ist nett, weil sie auch im Leerlauf funktioniert. Um nur den Dateinamen zu erhalten, können Sie os.path.basename (sys.argv [0])
Steven Bluen

Noch wichtiger ist, dass dies nur innerhalb der Hauptdatei funktioniert. Verwenden Sie dies nicht, __file__sondern stattdessen.
Apollys unterstützt Monica

WAS!!! Hast du das überhaupt versucht? Genau das Gegenteil ist der Fall. Der Fragesteller fragte nach dem Namen des laufenden Python-Skripts - nicht nach der Python-Datei, die gerade ausgeführt wird. Stellen Sie sich vor, Sie haben ein Skript, das im Fehlerfall den Skriptnamen zusammen mit den zulässigen Argumenten druckt. Sie fügen dies mit einer dieser beiden Techniken in eine Funktion ein. Irgendwann entscheiden Sie sich, die Funktion in eine externe Bibliothek zu verschieben. Möchten Sie den Namen des ausgeführten Hauptskripts oder den Namen der ausgeführten Bibliotheksdatei drucken?
John Deighan

71

Der Vollständigkeit halber hielt ich es für sinnvoll, die verschiedenen möglichen Ergebnisse zusammenzufassen und Referenzen für das genaue Verhalten der einzelnen zu liefern:

  • __file__ist die aktuell ausgeführte Datei, wie in der offiziellen Dokumentation beschrieben :

    __file__ist der Pfadname der Datei, aus der das Modul geladen wurde, wenn es aus einer Datei geladen wurde. Das __file__Attribut fehlt möglicherweise für bestimmte Modultypen, z. B. C- Module, die statisch mit dem Interpreter verknüpft sind. Bei Erweiterungsmodulen, die dynamisch aus einer gemeinsam genutzten Bibliothek geladen werden, ist dies der Pfadname der gemeinsam genutzten Bibliotheksdatei.

    Von Python3.4 ab, pro Ausgabe 18.416 , __file__ist immer ein absoluter Pfad, es sei denn , die aktuell ausgeführte Datei ist ein Skript , das direkt (mit der nicht über den Interpreter ausgeführt wurde -munter Verwendung eines relativen Pfadbefehlszeilenoption).

  • __main__.__file__(muss importiert werden __main__) greift einfach auf das oben genannte __file__Attribut des Hauptmoduls zu , z. B. des Skripts, das über die Befehlszeile aufgerufen wurde.

  • sys.argv[0](muss importiert werden sys) ist der Skriptname, der über die Befehlszeile aufgerufen wurde und möglicherweise ein absoluter Pfad ist, wie in der offiziellen Dokumentation beschrieben :

    argv[0]ist der Skriptname (es hängt vom Betriebssystem ab, ob dies ein vollständiger Pfadname ist oder nicht). Wenn der Befehl mit der -cBefehlszeilenoption für den Interpreter ausgeführt wurde, argv[0]wird er auf die Zeichenfolge gesetzt '-c'. Wenn kein Skriptname an den Python-Interpreter übergeben wurde, argv[0]ist dies die leere Zeichenfolge.

    Wie in einer anderen Antwort auf diese Frage erwähnt , zeigen Python- Skripte, die über Tools wie py2exe oder PyInstaller in eigenständige ausführbare Programme konvertiert wurden, bei Verwendung dieses Ansatzes möglicherweise nicht das gewünschte Ergebnis an (dh sys.argv[0]sie enthalten eher den Namen der ausführbaren Datei als den Namen der Python- Hauptdatei in dieser ausführbaren Datei).

  • Wenn keine der oben genannten Optionen zu funktionieren scheint, wahrscheinlich aufgrund eines unregelmäßigen Importvorgangs, kann sich das Inspektionsmodul als nützlich erweisen. Insbesondere könnte das Aufrufen von inspect.getfile(...)on inspect.currentframe()funktionieren, obwohl letzteres zurückkehren würde ,None wenn es in einer Implementierung ohne Python- Stack-Frame ausgeführt wird.


Umgang mit symbolischen Links

Wenn das aktuelle Skript eine symbolische Verknüpfung ist, geben alle oben genannten Elemente den Pfad der symbolischen Verknüpfung und nicht den Pfad der realen Datei zurück und os.path.realpath(...)sollten aufgerufen werden, um letztere zu extrahieren.


Weitere Manipulationen, die den tatsächlichen Dateinamen extrahieren

os.path.basename(...)kann auf einem der oben genannten Punkte aufgerufen werden, um den tatsächlichen Dateinamen zu extrahieren, und os.path.splitext(...)kann auf dem tatsächlichen Dateinamen aufgerufen werden, um sein Suffix wie in abzuschneiden os.path.splitext(os.path.basename(...)).

Ab Python 3.4 kann gemäß PEP 428 die PurePathKlasse des pathlibModuls auch für alle oben genannten Zwecke verwendet werden. Insbesondere pathlib.PurePath(...).nameextrahiert die tatsächlichen Dateinamen und pathlib.PurePath(...).stemextrahiert die tatsächlichen Dateinamen ohne seine Suffix.


66

Beachten Sie, __file__dass die Datei, in der sich dieser Code befindet, importiert werden kann und sich von der zu interpretierenden Hauptdatei unterscheidet. Um die Hauptdatei zu erhalten, kann das spezielle Modul __main__ verwendet werden:

import __main__ as main
print(main.__file__)

Beachten Sie, dass dies __main__.__file__in Python 2.7 funktioniert, jedoch nicht in 3.2. Verwenden Sie daher die oben beschriebene Import-as-Syntax, um es portabel zu machen.


Dies funktioniert in vielen Fällen, aber nicht, wenn ich das rPythonPaket aus der RSprache verwende. Das muss ein Ausnahmefall sein, der einfach zu schwer zu handhaben ist.
Leonid

In der Tat bettet das rPython-Paket den Python-Interpreter ein, was bedeutet, dass es keine 'Haupt'-Datei gibt, wie es der Fall ist, wenn Python alleine ausgeführt wird (Sie werden das gleiche Verhalten feststellen, wenn Python eingebettet ist). Es wird __main__intern importiert , um Variablen zwischen Rund zu übergeben python. Daher wäre es relativ einfach, es __main__.__file__vor dem Aufrufen von etwas anderem festzulegen, aber ich bin mir nicht einmal sicher, welcher Wert in diesem Fall angemessen wäre.
Perkins

42

Die obigen Antworten sind gut. Aber ich fand diese Methode unter Verwendung der obigen Ergebnisse effizienter.
Dies führt dazu, dass der tatsächliche Name der Skriptdatei kein Pfad ist.

import sys    
import os    
file_name =  os.path.basename(sys.argv[0])

1
Ich mag es auch, die Erweiterung abzuspalten, also benutze ich: os.path.splitext (os.path.basename (sys.argv [0])) [0]
RufusVS

19

Für moderne Python-Versionen (3.4+) Path(__file__).namesollte idiomatischer sein. Außerdem Path(__file__).stemhaben Sie die Skriptnamen ohne die .pyErweiterung.


NameError: Name 'Pfad' ist nicht definiert
RufusVS

5
Du solltest from pathlib import Pathzuerst.
Emil Melnikov

"modern" bedeutet Python 3.x?
Einpoklum

1
@einpoklum pathlibwurde in Python 3.4 eingeführt, daher sollte es ab Python 3.4 funktionieren.
Andrey Semakin


9

Hinweis: Wenn Sie Python 3+ verwenden, sollten Sie stattdessen die Funktion print () verwenden

Angenommen, der Dateiname ist foo.pydas folgende Snippet

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

oder

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

Wie bei anderen Erweiterungen mit mehr Zeichen, zum Beispiel dem Dateinamen foo.pypy

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

Wenn Sie aus einem absoluten Pfad extrahieren möchten

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

wird ausgegeben foo


1
sys.argv [0] [: - 3] würde tun
kon psych

@konpsych das ist eleganter
xtonousou

Es gibt einen großen Unterschied zwischen __file__und sys.argv[0], siehe stackoverflow.com/questions/5851588/…
Maksym Ganenko

8

Das erste Argument in sys ist der aktuelle Dateiname, damit dies funktioniert

   import sys
   print sys.argv[0] # will print the file name

7

Wenn Sie einen ungewöhnlichen Import durchführen (z. B. eine Optionsdatei), versuchen Sie Folgendes:

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

Beachten Sie, dass dadurch der absolute Pfad zur Datei zurückgegeben wird.


3

Wir können dies versuchen, um den aktuellen Skriptnamen ohne Erweiterung zu erhalten.

import os

script_name = os.path.splitext(os.path.basename(__file__))[0]

2

Da das OP nach dem Namen der aktuellen Skriptdatei gefragt hat, würde ich es vorziehen

import os
os.path.split(sys.argv[0])[1]

1

Alle diese Antworten sind großartig, haben aber einige Probleme, die Sie möglicherweise nicht auf den ersten Blick sehen.

Lassen Sie uns definieren, was wir wollen - wir wollen den Namen des Skripts, das ausgeführt wurde, nicht den Namen des aktuellen Moduls - also __file__funktioniert es nur, wenn es im ausgeführten Skript verwendet wird, nicht in einem importierten Modul. sys.argvist auch fraglich - was wäre, wenn Ihr Programm von pytest aufgerufen würde? oder Pydoc Runner? oder wenn es von uwsgi aufgerufen wurde?

und - es gibt eine dritte Methode, um den Skriptnamen zu erhalten, die ich in den Antworten nicht gesehen habe - Sie können den Stapel überprüfen.

Ein weiteres Problem ist, dass Sie (oder ein anderes Programm) mit sys.argvund manipulieren können__main__.__file__ - es könnte vorhanden sein, es könnte nicht sein. Es könnte gültig sein oder nicht. Zumindest können Sie überprüfen, ob das Skript (das gewünschte Ergebnis) vorhanden ist!

Meine Bibliothek bitranox / lib_programname bei github macht genau das:

  • Überprüfen Sie, ob __main__vorhanden
  • Überprüfen Sie, ob __main__.__file__vorhanden
  • gibt __main__.__file__ein gültiges Ergebnis (existiert dieses Skript?)
  • wenn nicht: check sys.argv:
  • gibt es pytest, docrunner usw. in der sys.argv? -> wenn ja, ignoriere das
  • Können wir hier ein gültiges Ergebnis erhalten?
  • Wenn nicht: Überprüfen Sie den Stapel und erhalten Sie möglicherweise das Ergebnis von dort
  • Wenn auch der Stapel kein gültiges Ergebnis liefert, lösen Sie eine Ausnahme aus.

durch diese Art und Weise, meine Lösung funktioniert so weit mit setup.py test, uwsgi, pytest, pycharm pytest, pycharm docrunner (doctest), dreampie,eclipse

Es gibt auch einen schönen Blog-Artikel über dieses Problem von Dough Hellman, "Bestimmen des Namens eines Prozesses aus Python".




0

Ab Python 3.5 können Sie einfach Folgendes tun:

from pathlib import Path
Path(__file__).stem

Weitere Informationen finden Sie hier: https://docs.python.org/3.5/library/pathlib.html#pathlib.PurePath.stem

Zum Beispiel habe ich eine Datei unter meinem Benutzerverzeichnis mit dem folgenden Namen test.py:

from pathlib import Path

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

Ausführen dieser Ausgänge:

>>> python3.6 test.py
test
test.py
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.