Come ottengo il percorso e il nome del file che è attualmente in esecuzione?


482

Ho degli script che chiamano altri file di script ma ho bisogno di ottenere il percorso del file che è attualmente in esecuzione all'interno del processo.

Ad esempio, supponiamo che io abbia tre file. Utilizzando execfile :

  • script_1.pychiamate script_2.py.
  • A sua volta, script_2.pychiama script_3.py.

Come posso ottenere il nome del file e il percorso di script_3.py, dal codice all'internoscript_3.py , senza dover passare tali informazioni come argomenti script_2.py?

(L'esecuzione os.getcwd()restituisce il percorso del file dello script iniziale originale non quello del file corrente.)



2
os.path.realpath ( file )
Girish Gupta

Risposte:


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
ATTENZIONE: questa chiamata non fornisce lo stesso risultato con ambienti diversi. Prendi in considerazione l'idea di accettare la risposta di Usagi di seguito: stackoverflow.com/a/6628348/851398
faraday

3
@faraday: potresti fornire un esempio? Ho risposto a una domanda simile usandoinspect.getabsfile() e ha funzionato per tutti i casi che ho provato.
jfs,

1
@Usagi è davvero la risposta migliore?
Dror,

4
nah user13993 ha inchiodato molto meglio
osirisgothra il

6
user13993 ha davvero risolto il problema. Dovrebbe essereos.path.realpath(__file__)
uchuugaka il

566
__file__

come altri hanno già detto. È inoltre possibile utilizzare os.path.realpath per eliminare i collegamenti simbolici:

import os

os.path.realpath(__file__)

14
Bisogna stare attenti con questo approccio perché a volte __file__restituisce 'script_name.py' e altre volte 'script_name.pyc'. Quindi l'output non è stabile.
meccatronico

27
Ma dal momento che stiamo usando solo il percorso di questo file è irrilevante.
Uwe Koloska,

5
questo è strano: quando si esegue dalla riga di comando "__file__"tra virgolette (come stringa) fornisce la directory da cui viene eseguito cmd, ma __file__ (senza virgolette indica il percorso del file di origine ... perché
Muon

7
@muon non viene eseguito alcun controllo sull'esistenza di una stringa di nome file passata e, poiché i percorsi dei file sono relativi al CWD, questo è ciò che la os.path.realpathfunzione assume che sia la dirparte del percorso. os.path.dirname(os.path.realpath(__file__))restituisce la directory con il file. os.path.dirname(os.path.realpath("__file__"))ritorna cwd. os.path.dirname(os.path.realpath("here_be_dragons"))restituisce anche cwd.
Jamie Bull,

86

Aggiornamento 28-11-2018:

Ecco un riassunto degli esperimenti con Python 2 e 3. Con

main.py - esegue foo.py
foo.py - esegue lib / bar.py
lib / bar.py - stampa le espressioni del percorso file

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

Per Python 2, potrebbe essere più chiaro passare ai pacchetti in modo da poterlo usare from lib import bar- basta aggiungere __init__.pyfile vuoti alle due cartelle.

Per Python 3, execfilenon esiste: l'alternativa più vicina è exec(open(<filename>).read()), sebbene ciò influisca sui frame dello stack. È più semplice da usare import fooe import lib.barnon è __init__.pynecessario alcun file.

Vedi anche Differenza tra import ed execfile


Risposta originale:

Ecco un esperimento basato sulle risposte in questo thread - con Python 2.7.10 su Windows.

Quelli basati sullo stack sono gli unici che sembrano dare risultati affidabili. Gli ultimi due hanno la sintassi più breve , ovvero -

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

Ecco a questi che vengono aggiunti al sistema come funzioni! Ringraziamo @Usagi e @pablog

Basato sui seguenti tre file, ed eseguendo main.py dalla sua cartella con python main.py(ho anche provato gli eseguibili con percorsi assoluti e chiamando da una cartella separata).

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

Penso che questo sia più pulito:

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

e ottiene le stesse informazioni di:

print inspect.getfile(inspect.currentframe())

Dove [0] è il frame corrente nello stack (parte superiore dello stack) e [1] è per il nome del file, aumentare per tornare indietro nello stack, ad es.

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

sarebbe il nome del file dello script che ha chiamato il frame corrente. Inoltre, l'uso di [-1] ti porterà in fondo allo stack, lo script chiamante originale.


4
Non raccomandare di fare affidamento sulla posizione all'interno della tupla. Non è affatto chiaro quali dati stai cercando di ottenere durante la lettura del codice.
jpmc26,

5
inspect.getfile()restituisce l' __file__attributo se viene passato un oggetto modulo. inspect.currentframe()restituisce il modulo. Ergo, questo è un modo costoso di dire __file__.
Martijn Pieters

inspect.stack()è una funzione piuttosto costosa, più che semplice inspect.currentframe(), e chiama anche inspect.getfile()un oggetto modulo.
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

1
Ho appena provato il commento di @Pat Notz. Penso che potresti semplicemente ottenere il nome del file __file__.
hlin117,

In Python3, os.path.dirnameti fornirà il percorso relativo da dove stai eseguendo lo script. ad esempio nel python ../../test.pyl' os.path.dirnamesarà ../../e non il percorso assoluto allo script. Stavo cercando abspath ma rimuovendo il nome della sceneggiatura. Il primo elemento di sys.path apparentemente è la risposta sys.path[0].
Aerijman

37

I suggerimenti contrassegnati come migliori sono tutti veri se lo script è costituito da un solo file.

Se vuoi scoprire il nome dell'eseguibile (ovvero il file root passato all'interprete python per il programma corrente) da un file che può essere importato come modulo, devi farlo (supponiamo che sia in un file chiamato foo.py ):

import inspect

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

Perché l'ultima cosa ( [-1]) nello stack è la prima cosa che è entrata (gli stack sono strutture di dati LIFO / FILO).

Quindi nel file bar.py se si import foostampa bar.py , piuttosto che foo.py , che sarebbe il valore di tutti questi:

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

Funziona bene ma non per il test unitario su eclipse, ho
/home/user/Softwares/eclipse/plugins/org.python.pydev_4.5.5.201603221110/pysrc

2
Questo è un modo costoso di compitare sys.modules['__main__'].__file__, davvero.
Martijn Pieters

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

questo ci darà solo il nome del file. cioè se abspath del file è c: \ abcd \ abc.py, la seconda riga stamperà abc.py


14

Non è del tutto chiaro cosa intendi con "il percorso del file che è attualmente in esecuzione all'interno del processo". sys.argv[0]di solito contiene la posizione dello script invocato dall'interprete Python. Controlla la documentazione del sistema per maggiori dettagli.

Come hanno sottolineato @Tim e @Pat Notz, l'attributo __file__ fornisce l'accesso a

il file da cui è stato caricato il modulo, se è stato caricato da un file


1
"print os.path.abspath ( file )" e "print inspect.getfile (inspect.currentframe ())" non funzionano quando passiamo il programma python a un exe win32. Funziona solo sys.argv [0]! :) ma ottieni solo il nome!
aF.

11

Ho uno script che deve funzionare in ambiente Windows. Questo codice snipped è quello con cui ho finito:

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

è una decisione piuttosto confusa. Ma non richiede librerie esterne ed è la cosa più importante nel mio caso.


1
Ho dovuto "importare os, sys" per questo, ma finora è la risposta migliore che in realtà restituisce solo il percorso senza un nome di file alla fine della stringa.
emmagras,

10

Prova questo,

import os
os.path.dirname(os.path.realpath(__file__))

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

Non c'è bisogno di ispezionare o qualsiasi altra biblioteca.

Questo ha funzionato per me quando ho dovuto importare uno script (da una directory diversa da quella eseguita), che utilizzava un file di configurazione che risiedeva nella stessa cartella dello script importato.


Ciò non produrrà la risposta desiderata se la directory di lavoro corrente (os.getcwd) è diversa dalla directory in cui si trova il file.
Cuscino di ferro

2
Come mai? Funziona bene per me in questo caso. Ottengo la directory in cui si trova il file.
Michael Mior

@IronPillow forse questa risposta ti aiuterà con ciò di cui hai bisogno. stackoverflow.com/a/41546830/3123191
Kwuite


6
import sys

print sys.path[0]

questo stamperebbe il percorso dello script attualmente in esecuzione


2
sys.path [0] è molto utile, ma fornisce il percorso di script1, non script3 come richiesto
James,

Almeno su OS X, con 2.7, non trovo che questo faccia qualcosa di affidabile. Funziona se si esegue direttamente lo stesso file. Non funziona da sostitu, specialmente da un uovo importato
uchuugaka


4

Puoi usare 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

Poiché Python 3 è abbastanza mainstream, volevo includere una pathlibrisposta, poiché credo che ora sia probabilmente uno strumento migliore per accedere alle informazioni su file e percorsi.

from pathlib import Path

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

Se state cercando la directory del file corrente, è facile come aggiungere .parentalla Path()dichiarazione:

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

3
import sys
print sys.argv[0]

10
Sfortunatamente questo funziona solo se lo script è stato chiamato con il suo percorso completo, perché restituisce solo il "primo argomento" sulla riga di comando, che è la chiamata allo script.
Cregox,

2

Questo dovrebbe funzionare:

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
Le risposte solo al codice sono scoraggiate. Si prega di aggiungere alcune spiegazioni su come questo risolve il problema o in che modo differisce dalle risposte esistenti. Dalla recensione
Nick,

1

Per ottenere la directory dello script in esecuzione

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

1

Ho sempre usato la funzione os di Current Working Directory, o CWD. Questo fa parte della libreria standard ed è molto facile da implementare. Ecco un esempio:

    import os
    base_directory = os.getcwd()

1
Potresti modificare la tua risposta in modo che si applichi alla domanda posta? Questa risposta non si applica alla domanda "Come ottengo il percorso e il nome del file che è attualmente in esecuzione? "
Marco

1
Questo fornisce il percorso da cui è stato eseguito il comando python. Quindi sembra funzionare quando si esegue il python script.pycomando nella stessa cartella in cui ci si trova già, quando in realtà è lo stesso che in esecuzione pwdsu Linux.
George,

0

Ho usato l'approccio con __file__
os.path.abspath(__file__)
ma c'è un piccolo trucco, restituisce il file .py quando il codice viene eseguito la prima volta, le esecuzioni successive danno il nome del file * .pyc,
quindi sono rimasto con:
inspect.getfile(inspect.currentframe())
o
sys._getframe().f_code.co_filename


0

Ho scritto una funzione che tiene conto del debugger di eclissi e unittest . Restituisce la cartella del primo script che si avvia. È possibile specificare facoltativamente __file__ var, ma la cosa principale è che non è necessario condividere questa variabile in tutta la gerarchia chiamante .

Forse puoi gestire altri casi particolari che non ho visto, ma per me va bene.

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

Per mantenere la coerenza della migrazione su più piattaforme (macOS / Windows / Linux), prova:

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


2
Questo è sbagliato. Questo ti porta il percorso corrente, ma non il percorso del file corrente.
Charles Plager,

0

Il modo più semplice è:

in script_1.py:

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

in script_2.py:

sys.argv[0]

PS: ci ho provato execfile, ma dato che legge script_2.py come una stringa, è sys.argv[0]tornato <string>.


0

Ecco cosa uso in modo da poter lanciare il mio codice ovunque senza problemi. __name__è sempre definito, ma __file__viene definito solo quando il codice viene eseguito come file (ad es. non in IDLE / iPython).

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

In alternativa, questo può essere scritto come:

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

-2

La maggior parte di queste risposte sono state scritte in Python versione 2.xo precedenti. In Python 3.x la sintassi per la funzione di stampa è cambiata per richiedere parentesi, ovvero print ().

Quindi, questa precedente risposta a punteggio elevato da 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

Diventa 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

-3

se vuoi solo il nome del file senza ./o .pypuoi provare questo

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

file_name stamperà testscript che puoi generare come vuoi cambiando l'indice all'interno di []


-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 () restituisce la directory WORKING corrente di PROCESS, non la directory del file attualmente in esecuzione. Questo potrebbe sembrare che restituisca i risultati corretti, ma ci sono molti casi in cui il risultato non sarebbe la directory principale del file corrente. Molto meglio usare os.path.dirname ( file ) come suggerito sopra.
Samaspin,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.