Wie erhalte ich den Pfad und den Namen der Datei, die gerade ausgeführt wird?

482

Ich habe Skripte, die andere Skriptdateien aufrufen, aber ich muss den Dateipfad der Datei abrufen, die derzeit im Prozess ausgeführt wird.

Nehmen wir zum Beispiel an, ich habe drei Dateien. Mit execfile :

  • script_1.pyAnrufe script_2.py.
  • script_2.pyAnrufe wiederum script_3.py.

Wie kann ich die Dateinamen und den Pfad erhalten script_3.py, von Code innerhalbscript_3.py , ohne aus , dass die Informationen als Argument zu übergeben script_2.py?

(Beim Ausführen wird os.getcwd()der Dateipfad des ursprünglichen Startskripts zurückgegeben, nicht der der aktuellen Datei.)

Strahl
quelle
2
os.path.realpath ( Datei )
Girish Gupta

Antworten:

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
Pat Notz
quelle
11
ACHTUNG: Dieser Aufruf liefert in verschiedenen Umgebungen nicht das gleiche Ergebnis. Betrachten wir die Annahme Usagis Antwort unten: stackoverflow.com/a/6628348/851398
faraday
3
@faraday: Könnten Sie ein Beispiel geben? Ich habe eine ähnliche Frage mitinspect.getabsfile() beantwortet und es hat in allen Fällen funktioniert, die ich versucht habe.
JFS
1
Ist @Usagi Antwort tatsächlich besser?
Dror
4
nah user13993 hat es viel besser geschafft
osirisgothra
6
user13993 hat es tatsächlich geschafft. Sollte seinos.path.realpath(__file__)
uchuugaka
566
__file__

wie andere gesagt haben. Möglicherweise möchten Sie auch os.path.realpath verwenden , um Symlinks zu entfernen :

import os

os.path.realpath(__file__)
user13993
quelle
14
Bei diesem Ansatz muss man vorsichtig sein, da manchmal __file__'script_name.py' und manchmal 'script_name.pyc' zurückgegeben wird. Die Ausgabe ist also nicht stabil.
Mechatroner
27
Da wir jedoch nur den Pfad dieser Datei verwenden, ist dies irrelevant.
Uwe Koloska
5
das ist seltsam: wenn von der Kommandozeile "__file__"in Anführungszeichen (als Zeichenfolge) ausgeführt wird, wird das Verzeichnis angegeben, von dem aus cmd ausgeführt wird, aber __file__ (ohne Anführungszeichen wird der Pfad zur Quelldatei angegeben ... warum ist das so
muon
7
@muon Es wird nicht überprüft, ob eine übergebene Dateinamenzeichenfolge vorhanden ist. Da Dateipfade relativ zum cwd sind, nimmt die os.path.realpathFunktion den dirTeil des Pfads an. os.path.dirname(os.path.realpath(__file__))Gibt das Verzeichnis mit der Datei zurück. os.path.dirname(os.path.realpath("__file__"))gibt cwd zurück. os.path.dirname(os.path.realpath("here_be_dragons"))gibt auch cwd zurück.
Jamie Bull
86

Update 2018-11-28:

Hier ist eine Zusammenfassung der Experimente mit Python 2 und 3. Mit

main.py - führt foo.py aus
foo.py - führt lib / bar.py
lib / bar.py aus - druckt Dateipfadausdrücke

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

Für Python 2 ist es möglicherweise klarer, zu Paketen zu wechseln, um diese zu verwenden. from lib import barFügen Sie einfach leere __init__.pyDateien zu den beiden Ordnern hinzu.

Für Python 3 execfilegibt es keine - die nächste Alternative ist exec(open(<filename>).read()), obwohl dies die Stapelrahmen betrifft. Es ist am einfachsten zu verwenden import foound import lib.bar- keine __init__.pyDateien erforderlich.

Siehe auch Unterschied zwischen Import und Execfile


Ursprüngliche Antwort:

Hier ist ein Experiment, das auf den Antworten in diesem Thread basiert - mit Python 2.7.10 unter Windows.

Die stapelbasierten sind die einzigen, die zuverlässige Ergebnisse zu liefern scheinen. Die letzten beiden haben die kürzeste Syntax , dh -

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

Hier ist, dass diese als Funktionen zu sys hinzugefügt werden! Gutschrift an @Usagi und @pablog

Basierend auf den folgenden drei Dateien und Ausführen von main.py aus dem Ordner mit python main.py(auch Execfiles mit absoluten Pfaden ausprobiert und Aufruf aus einem separaten Ordner).

C: \ Dateipfade \ main.py: execfile('foo.py')
C: \ Dateipfade \ foo.py: execfile('lib/bar.py')
C: \ Dateipfade \ 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
Brian Burns
quelle
72

Ich finde das sauberer:

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

und erhält die gleichen Informationen wie:

print inspect.getfile(inspect.currentframe())

Wenn [0] der aktuelle Frame im Stapel ist (oben im Stapel) und [1] der Dateiname ist, erhöhen Sie den Wert, um im Stapel rückwärts zu gehen, d. H.

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

wäre der Dateiname des Skripts, das den aktuellen Frame aufgerufen hat. Wenn Sie [-1] verwenden, gelangen Sie zum Ende des Stapels, dem ursprünglichen aufrufenden Skript.

Usagi
quelle
4
Verlassen Sie sich nicht auf die Position im Tupel. Es ist überhaupt nicht klar, welche Daten Sie beim Lesen des Codes abrufen möchten.
jpmc26
5
inspect.getfile()Gibt das __file__Attribut zurück, wenn ein Modulobjekt übergeben wurde. inspect.currentframe()gibt das Modul zurück. Ergo ist dies eine teure Art zu sagen __file__.
Martijn Pieters
inspect.stack()ist eine ziemlich teure Funktion, mehr als nur inspect.currentframe(), und sie ruft auch inspect.getfile()ein Modulobjekt auf.
Martijn Pieters
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
Neal Xiong
quelle
1
Ich habe gerade den Kommentar von @Pat Notz ausprobiert. Ich denke, Sie könnten einfach den Dateinamen durchbekommen __file__.
hlin117
In Python3 erhalten os.path.dirnameSie den relativen Pfad, von dem aus Sie das Skript ausführen . zB in python ../../test.pyder os.path.dirnamesein wird ../../und nicht der absolute Pfad zum Skript. Ich suchte nach Abspath, entfernte aber den Namen des Skripts. Das erste Element von sys.path ist anscheinend die Antwort sys.path[0].
Aerijman
37

Die als am besten gekennzeichneten Vorschläge sind alle wahr, wenn Ihr Skript nur aus einer Datei besteht.

Wenn Sie den Namen der ausführbaren Datei (dh die Stammdatei, die für das aktuelle Programm an den Python-Interpreter übergeben wurde) aus einer Datei herausfinden möchten, die möglicherweise als Modul importiert wird, müssen Sie dies tun (nehmen wir an, dass sich diese in einer Datei befindet benannt foo.py ):

import inspect

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

Weil das Letzte ( [-1]) auf dem Stapel das erste ist, was hineingegangen ist (Stapel sind LIFO / FILO-Datenstrukturen).

Dann in der Datei bar.py , wenn Sie import foowerden es drucken bar.py , anstatt foo.py , was der Wert aller von diesen sein würde:

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

quelle
Es funktioniert gut, aber nicht für Unit-Tests auf Eclipse. Ich habe /home/user/Softwares/eclipse/plugins/org.python.pydev_4.5.5.201603221110/pysrc
hayj
2
Dies ist sys.modules['__main__'].__file__wirklich eine teure Art der Rechtschreibung .
Martijn Pieters
14
import os
print os.path.basename(__file__)

Dies gibt uns nur den Dateinamen. dh wenn abspath der Datei c: \ abcd \ abc.py ist, wird in der zweiten Zeile abc.py gedruckt

vishal ekhe
quelle
14

Es ist nicht ganz klar, was Sie unter "dem Dateipfad der Datei verstehen, die derzeit im Prozess ausgeführt wird". sys.argv[0]Enthält normalerweise den Speicherort des Skripts, das vom Python-Interpreter aufgerufen wurde. Überprüf denWeitere Informationen finden sys-Dokumentation .

Wie @Tim und @Pat Notz hervorgehoben haben, bietet das Attribut __file__ Zugriff auf

die Datei, aus der das Modul geladen wurde, wenn es aus einer Datei geladen wurde

Blair Conrad
quelle
1
"print os.path.abspath ( file )" und "print inspect.getfile (inspect.currentframe ())" funktionieren nicht, wenn wir das Python-Programm an eine win32-Exe übergeben. Nur sys.argv [0] funktioniert! :) aber du bekommst nur den Namen!
aF.
11

Ich habe ein Skript, das unter Windows-Umgebung funktionieren muss. Mit diesem Code habe ich Folgendes beendet:

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

Es ist eine ziemlich hackige Entscheidung. Aber es erfordert keine externen Bibliotheken und es ist das Wichtigste in meinem Fall.

Garmoncheg
quelle
1
Ich musste dafür "os, sys" importieren, aber bisher ist es die beste Antwort, die tatsächlich nur den Pfad ohne Dateinamen am Ende der Zeichenfolge zurückgibt.
Emmagras
10

Versuche dies,

import os
os.path.dirname(os.path.realpath(__file__))
Soumyajit
quelle
8
import os
os.path.dirname(os.path.abspath(__file__))

Keine Notwendigkeit für Inspektion oder andere Bibliothek.

Dies funktionierte für mich, als ich ein Skript (aus einem anderen Verzeichnis als dem ausgeführten Skript) importieren musste, das eine Konfigurationsdatei verwendete, die sich im selben Ordner wie das importierte Skript befand.

Kwuite
quelle
Dies führt nicht zu der gewünschten Antwort, wenn sich das aktuelle Arbeitsverzeichnis (os.getcwd) von dem Verzeichnis unterscheidet, in dem sich die Datei befindet.
Eisen - Kissen
2
Wie das? Funktioniert in diesem Fall gut für mich. Ich bekomme das Verzeichnis, in dem sich die Datei befindet.
Michael Mior
@IronPillow Vielleicht hilft Ihnen diese Antwort bei dem, was Sie brauchen. stackoverflow.com/a/41546830/3123191
Kwuite
6
import sys

print sys.path[0]

Dies würde den Pfad des aktuell ausgeführten Skripts drucken

appusajeev
quelle
2
sys.path [0] ist sehr nützlich, gibt aber den Pfad von script1 an, nicht script3 wie angefordert
James
Zumindest unter OS X mit 2.7 finde ich, dass dies nichts Zuverlässiges bewirkt. Es funktioniert, wenn dieselbe Datei direkt ausgeführt wird. Funktioniert nicht von repl, besonders von einem importierten Ei
uchuugaka
5

Ich denke, es __file__ klingt nur so, als ob Sie auch das Inspect-Modul auschecken möchten .

Pat Notz
quelle
Ahhh ... Execfile ist schwierig. Siehe meinen anderen Beitrag über die Verwendung des Inspektionsmoduls.
Pat Notz
4

Sie können verwenden 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'
PabloG
quelle
4

Da Python 3 ziemlich Mainstream ist, wollte ich eine pathlibAntwort hinzufügen, da ich glaube, dass es jetzt wahrscheinlich ein besseres Werkzeug für den Zugriff auf Datei- und Pfadinformationen ist.

from pathlib import Path

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

Wenn Sie das Verzeichnis der aktuellen Datei suchen, ist es so einfach wie das Hinzufügen .parentzur Path()Anweisung:

current_path: Path = Path(__file__).parent.resolve()
Doug
quelle
3
import sys
print sys.argv[0]
WBAR
quelle
10
Leider funktioniert dies nur, wenn das Skript mit seinem vollständigen Pfad aufgerufen wurde, da es nur das "erste Argument" in der Befehlszeile zurückgibt, bei dem es sich um den Aufruf des Skripts handelt.
Cregox
2

Das sollte funktionieren:

import os,sys
filename=os.path.basename(os.path.realpath(sys.argv[0]))
dirname=os.path.dirname(os.path.realpath(sys.argv[0]))
Jahid
quelle
2
print(__file__)
print(__import__("pathlib").Path(__file__).parent)
BaiJiFeiLong
quelle
4
Von nur Code-Antworten wird abgeraten. Bitte fügen Sie eine Erklärung hinzu, wie dies das Problem löst oder wie sich dies von den vorhandenen Antworten unterscheidet. Aus der Bewertung
Nick
1

Um das Verzeichnis der Ausführung des Skripts zu erhalten

 print os.path.dirname( inspect.getfile(inspect.currentframe()))
pbaranski
quelle
1

Ich habe immer nur die Betriebssystemfunktion von Current Working Directory oder CWD verwendet. Dies ist Teil der Standardbibliothek und sehr einfach zu implementieren. Hier ist ein Beispiel:

    import os
    base_directory = os.getcwd()
Ethan J.
quelle
1
Könnten Sie Ihre Antwort so ändern, dass sie für die gestellte Frage gilt? Diese Antwort gilt nicht für die Frage "Wie erhalte ich den Pfad und den Namen der Datei, die gerade ausgeführt wird? "
Marco
1
Dies gibt den Pfad an, von dem aus Sie den Python-Befehl ausgeführt haben. Es scheint also zu funktionieren, wenn Sie den python script.pyBefehl in demselben Ordner ausführen, in dem Sie sich bereits befinden. In Wirklichkeit ist es dasselbe wie unter pwdLinux.
George
0

Ich habe den Ansatz mit __file__ verwendet,
os.path.abspath(__file__)
aber es gibt einen kleinen Trick: Er gibt die .py-Datei zurück, wenn der Code zum ersten Mal ausgeführt wird. Bei den nächsten Ausführungen wird der Name * .pyc-Datei angegeben,
sodass ich bei:
inspect.getfile(inspect.currentframe())
oder blieb
sys._getframe().f_code.co_filename

mik80
quelle
0

Ich habe eine Funktion geschrieben, die Eclipse Debugger und Unittest berücksichtigt . Es gibt den Ordner des ersten Skripts zurück, das Sie starten. Sie können optional die Variable __file__ angeben , aber die Hauptsache ist, dass Sie diese Variable nicht für Ihre gesamte aufrufende Hierarchie freigeben müssen .

Vielleicht können Sie mit anderen Stapeln bestimmter Fälle umgehen, die ich nicht gesehen habe, aber für mich ist es in Ordnung.

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_))
hayj
quelle
0

Versuchen Sie Folgendes, um die Konsistenz der Migration zwischen Plattformen (macOS / Windows / Linux) zu gewährleisten:

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

Qiao Zhang
quelle
2
Das ist falsch. Dadurch erhalten Sie den aktuellen Pfad, jedoch nicht den Pfad der aktuellen Datei.
Charles Plager
0

Der einfachste Weg ist:

in script_1.py:

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

in script_2.py:

sys.argv[0]

PS: Ich habe es versucht execfile, aber da es script_2.py als String liest, wurde sys.argv[0]zurückgegeben <string>.

Lucas Azevedo
quelle
0

Hier ist, was ich verwende, damit ich meinen Code ohne Probleme überall hin werfen kann. __name__wird immer definiert, aber __file__nur definiert, wenn der Code als Datei ausgeführt wird (z. B. nicht in IDLE / iPython).

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

Alternativ kann dies wie folgt geschrieben werden:

self_name = globals().get('__file__', locals().get('__file__', __name__))
craymichael
quelle
-2

Die meisten dieser Antworten wurden in Python Version 2.x oder früher geschrieben. In Python 3.x wurde die Syntax für die Druckfunktion dahingehend geändert, dass Klammern erforderlich sind, dh print ().

Also, diese frühere Highscore-Antwort von user13993 in 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

Wird in 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
user3339488
quelle
-3

Wenn Sie nur den Dateinamen ohne ./oder möchten .py, können Sie dies versuchen

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

file_name druckt das Testskript, das Sie generieren können, indem Sie den Index in [] ändern.

Sapam
quelle
-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)
jscabuzzo
quelle
7
os.getcwd () gibt das aktuelle WORKING-Verzeichnis des PROCESS zurück, nicht das Verzeichnis der aktuell ausgeführten Datei. Dies scheint die korrekten Ergebnisse zurückzugeben, aber es gibt viele Fälle, in denen das Ergebnis nicht das übergeordnete Verzeichnis der aktuellen Datei ist. Es ist viel besser, os.path.dirname ( Datei ) wie oben vorgeschlagen zu verwenden.
Samaspin