Comment obtenir le chemin et le nom du fichier en cours d'exécution?

482

J'ai des scripts appelant d'autres fichiers de script, mais j'ai besoin d'obtenir le chemin du fichier en cours d'exécution dans le processus.

Par exemple, supposons que j'ai trois fichiers. Utiliser execfile :

  • script_1.pyles appels script_2.py.
  • À son tour, les script_2.pyappels script_3.py.

Comment puis-je obtenir le nom et le chemin du fichier script_3.py, à partir du code à l'intérieurscript_3.py , sans avoir à transmettre ces informations comme arguments script_2.py?

(L'exécution os.getcwd()renvoie le chemin de fichier du script de démarrage d'origine et non celui du fichier en cours.)

Rayon
la source
2
os.path.realpath ( fichier )
Girish Gupta

Réponses:

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
la source
11
ATTENTION: Cet appel ne donne pas le même résultat avec des environnements différents. Envisagez d'accepter la réponse d'Usagi ci-dessous: stackoverflow.com/a/6628348/851398
faraday
3
@faraday: Pourriez-vous donner un exemple? J'ai répondu à une question similaire en utilisantinspect.getabsfile() et cela a fonctionné pour tous les cas que j'ai essayés.
jfs
1
La réponse à @Usagi est-elle en effet meilleure?
Dror
4
nah user13993 a mieux
réussi
6
user13993 l'a bien cloué. Devrait êtreos.path.realpath(__file__)
uchuugaka
566
__file__

comme d'autres l'ont dit. Vous pouvez également utiliser os.path.realpath pour éliminer les liens symboliques:

import os

os.path.realpath(__file__)
user13993
la source
14
Il faut être prudent avec cette approche car parfois __file__retourne 'script_name.py', et parfois 'script_name.pyc'. La sortie n'est donc pas stable.
mechatroner
27
Mais puisque nous utilisons uniquement le chemin de ce fichier, cela n'est pas pertinent.
Uwe Koloska
5
c'est bizarre: lors de l'exécution à partir de la ligne de commande "__file__"entre guillemets (sous forme de chaîne) donne le répertoire à partir duquel cmd est exécuté, mais __file__ (sans guillemets donne le chemin d'accès au fichier source ... pourquoi est-ce
muon
7
@muon il n'y a aucune vérification effectuée pour savoir si une chaîne de nom de fichier transmise existe, et puisque les chemins de fichier sont relatifs au cwd, c'est ce que la os.path.realpathfonction suppose que la dirpartie du chemin soit. os.path.dirname(os.path.realpath(__file__))retourne le répertoire avec le fichier. os.path.dirname(os.path.realpath("__file__"))renvoie cwd. os.path.dirname(os.path.realpath("here_be_dragons"))renvoie également cwd.
Jamie Bull
86

Mise à jour 2018-11-28:

Voici un résumé des expériences avec Python 2 et 3. Avec

main.py - exécute foo.py
foo.py - exécute lib / bar.py
lib / bar.py - imprime les expressions de chemin de fichier

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

Pour Python 2, il peut être plus clair de passer aux packages, vous pouvez donc l'utiliser from lib import bar- ajoutez simplement des __init__.pyfichiers vides aux deux dossiers.

Pour Python 3, execfilen'existe pas - l'alternative la plus proche est exec(open(<filename>).read()), bien que cela affecte les cadres de pile. Il est plus simple à utiliser import fooet import lib.bar- aucun __init__.pyfichier n'est nécessaire.

Voir aussi Différence entre import et execfile


Réponse originale:

Voici une expérience basée sur les réponses de ce fil - avec Python 2.7.10 sous Windows.

Les piles basées sur la pile sont les seules qui semblent donner des résultats fiables. Les deux derniers ont la syntaxe la plus courte , c'est-à-dire -

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

Voici à ces ajouts à sys en tant que fonctions! Crédit à @Usagi et @pablog

Sur la base des trois fichiers suivants, et en exécutant main.py à partir de son dossier avec python main.py(également des fichiers exécutés essayés avec des chemins absolus et appelant à partir d'un dossier séparé).

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
Brian Burns
la source
72

Je pense que c'est plus propre:

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

et obtient les mêmes informations que:

print inspect.getfile(inspect.currentframe())

Où [0] est l'image actuelle dans la pile (haut de la pile) et [1] pour le nom du fichier, augmentez pour revenir en arrière dans la pile, c.-à-d.

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

serait le nom de fichier du script qui a appelé l'image actuelle. De plus, l'utilisation de [-1] vous amènera au bas de la pile, le script d'appel d'origine.

Usagi
la source
4
Ne recommande pas de se fier à la position à l'intérieur du tuple. Il n'est pas du tout clair quelles données vous essayez d'obtenir en lisant le code.
jpmc26
5
inspect.getfile()retourne l' __file__attribut si passé un objet module. inspect.currentframe()renvoie le module. Ergo, c'est une façon coûteuse de dire __file__.
Martijn Pieters
inspect.stack()est une fonction assez chère, plus que juste inspect.currentframe(), et elle fait aussi appel inspect.getfile()à un objet module.
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
la source
1
Je viens d'essayer le commentaire de @Pat Notz. Je pense que vous pouvez simplement obtenir le nom de fichier __file__.
hlin117
En Python3, os.path.dirnamevous donnera le chemin relatif à partir duquel vous exécutez le script. par exemple dans python ../../test.pyle os.path.dirnamesera ../../et non le chemin absolu vers le script. Je cherchais l'abspath mais en supprimant le nom du script. Le premier élément de sys.path est apparemment la réponse sys.path[0].
aerijman
37

Les suggestions marquées comme les meilleures sont toutes vraies si votre script se compose d'un seul fichier.

Si vous voulez connaître le nom de l'exécutable (c'est-à-dire le fichier racine passé à l'interpréteur python pour le programme actuel) à partir d'un fichier qui peut être importé en tant que module, vous devez le faire (supposons que cela se trouve dans un fichier nommé foo.py ):

import inspect

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

Parce que la dernière chose ( [-1]) sur la pile est la première chose qui y est entrée (les piles sont des structures de données LIFO / FILO).

Ensuite, dans le fichier bar.py si vous import fooimprimez bar.py , plutôt que foo.py , qui serait la valeur de tous ces éléments:

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

la source
Cela fonctionne bien mais pas pour le test unitaire sur eclipse, j'ai eu /home/user/Softwares/eclipse/plugins/org.python.pydev_4.5.5.201603221110/pysrc
hayj
2
C'est sys.modules['__main__'].__file__vraiment une façon coûteuse d'orthographe .
Martijn Pieters
14
import os
print os.path.basename(__file__)

cela nous donnera uniquement le nom du fichier. c'est-à-dire si l'abspath du fichier est c: \ abcd \ abc.py alors la deuxième ligne affichera abc.py

vishal ekhe
la source
14

Il n'est pas tout à fait clair ce que vous entendez par "le chemin de fichier du fichier qui s'exécute actuellement dans le processus". sys.argv[0]contient généralement l'emplacement du script qui a été invoqué par l'interpréteur Python. Consultez la documentation sys pour plus de détails.

Comme l'ont souligné @Tim et @Pat Notz, l'attribut __file__ donne accès à

le fichier à partir duquel le module a été chargé, s'il a été chargé à partir d'un fichier

Blair Conrad
la source
1
"print os.path.abspath ( file )" et "print inspect.getfile (inspect.currentframe ())" ne fonctionnent pas lorsque nous passons le programme python à un exe win32. Seul sys.argv [0] fonctionne! :) mais vous n'obtenez que le nom!
aF.
11

J'ai un script qui doit fonctionner sous environnement Windows. Ce code coupé est ce que j'ai fini avec:

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

c'est une décision assez bidon. Mais cela ne nécessite aucune bibliothèque externe et c'est la chose la plus importante dans mon cas.

garmoncheg
la source
1
J'ai dû "importer os, sys" pour cela, mais jusqu'à présent, c'est la meilleure réponse qui renvoie en fait juste le chemin sans nom de fichier à la fin de la chaîne.
emmagras
10

Essaye ça,

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

Pas besoin d'inspecter ou de toute autre bibliothèque.

Cela a fonctionné pour moi lorsque j'ai dû importer un script (à partir d'un répertoire différent puis du script exécuté), qui utilisait un fichier de configuration résidant dans le même dossier que le script importé.

Kwuite
la source
Cela ne produira pas la réponse souhaitée si le répertoire de travail actuel (os.getcwd) est différent du répertoire dans lequel se trouve le fichier.
Oreiller en fer du
2
Comment? Fonctionne bien pour moi dans ce cas. J'obtiens le répertoire dans lequel se trouve le fichier.
Michael Mior
@IronPillow peut-être que cette réponse vous aidera avec ce dont vous avez besoin. stackoverflow.com/a/41546830/3123191
Kwuite
6
import sys

print sys.path[0]

cela afficherait le chemin du script en cours d'exécution

appusajeev
la source
2
sys.path [0] est très utile, mais donne le chemin de script1, pas script3 comme demandé
James
Au moins sur OS X, avec 2.7, je ne trouve pas que cela fasse quoi que ce soit de fiable. Cela fonctionne si vous exécutez directement le même fichier. Ne fonctionne pas à partir de repl, en particulier à partir d'un œuf importé
uchuugaka
5

Je pense que c'est juste __file__ comme si vous souhaitiez peut-être également vérifier le module d'inspection .

Pat Notz
la source
Ahhh ... execfile est délicat. Voir mon autre article sur l'utilisation du module d'inspection.
Pat Notz, le
4

Vous pouvez utiliser 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
la source
4

Étant donné que Python 3 est assez courant, je voulais inclure une pathlibréponse, car je pense que c'est probablement maintenant un meilleur outil pour accéder aux informations sur les fichiers et les chemins.

from pathlib import Path

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

Si vous recherchez le répertoire du fichier en cours, c'est aussi simple que d'ajouter .parentà la Path()déclaration:

current_path: Path = Path(__file__).parent.resolve()
Doug
la source
3
import sys
print sys.argv[0]
WBAR
la source
10
Malheureusement, cela ne fonctionne que si le script a été appelé avec son chemin d'accès complet, car il ne renvoie que le "premier argument" sur la ligne de commande, qui est l'appel au script.
cregox
2

Cela devrait fonctionner:

import os,sys
filename=os.path.basename(os.path.realpath(sys.argv[0]))
dirname=os.path.dirname(os.path.realpath(sys.argv[0]))
Jahid
la source
2
print(__file__)
print(__import__("pathlib").Path(__file__).parent)
BaiJiFeiLong
la source
4
Seules les réponses codées sont déconseillées. Veuillez ajouter quelques explications sur la façon dont cela résout le problème, ou en quoi cela diffère des réponses existantes. De l'avis
Nick
1

Pour obtenir le répertoire d'exécution du script

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

J'ai toujours utilisé la fonction os de Current Working Directory, ou CWD. Cela fait partie de la bibliothèque standard et est très facile à implémenter. Voici un exemple:

    import os
    base_directory = os.getcwd()
Ethan J.
la source
1
Pourriez-vous modifier votre réponse pour qu'elle s'applique à la question posée? Cette réponse ne s'applique pas à la question "Comment obtenir le chemin et le nom du fichier en cours d'exécution? "
Marco
1
Cela donne le chemin à partir duquel vous avez exécuté la commande python. Cela semble donc fonctionner lorsque vous exécutez la python script.pycommande dans le même dossier que vous êtes déjà, alors qu'en réalité, c'est la même chose que l'exécution pwdsur Linux.
George
0

J'ai utilisé l'approche avec __file__
os.path.abspath(__file__)
mais il y a une petite astuce, elle retourne le fichier .py lorsque le code est exécuté la première fois, les prochaines exécutions donnent le nom du fichier * .pyc
donc je suis resté avec:
inspect.getfile(inspect.currentframe())
ou
sys._getframe().f_code.co_filename

mik80
la source
0

J'ai écrit une fonction qui prend en compte le débogueur d' éclipse et unittest . Il renvoie le dossier du premier script que vous lancez. Vous pouvez éventuellement spécifier la var __file__ , mais l'essentiel est que vous n'avez pas à partager cette variable dans toute votre hiérarchie d'appel .

Peut-être que vous pouvez gérer d'autres empiler des cas particuliers que je n'ai pas vus, mais pour moi, ça va.

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
la source
0

Pour conserver la cohérence de la migration entre les plates-formes (macOS / Windows / Linux), essayez:

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

Qiao Zhang
la source
2
C'est faux. Cela vous donne le chemin actuel, mais pas le chemin du fichier actuel.
Charles Plager
0

Le moyen le plus simple est:

dans script_1.py:

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

dans script_2.py:

sys.argv[0]

PS: J'ai essayé execfile, mais comme il lit script_2.py sous forme de chaîne, je suis sys.argv[0]retourné <string>.

Lucas Azevedo
la source
0

Voici ce que j'utilise pour pouvoir lancer mon code n'importe où sans problème. __name__est toujours défini, mais __file__n'est défini que lorsque le code est exécuté en tant que fichier (par exemple pas dans IDLE / iPython).

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

Alternativement, cela peut s'écrire:

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

La plupart de ces réponses ont été écrites en Python version 2.x ou antérieure. Dans Python 3.x, la syntaxe de la fonction d'impression a changé pour exiger des parenthèses, c'est-à-dire print ().

Donc, cette réponse antérieure au meilleur score de user13993 en 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

Devient en 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
la source
-3

si vous voulez juste le nom de fichier sans ./ou .pyvous pouvez essayer ceci

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

file_name affichera le script de test, vous pouvez générer ce que vous voulez en modifiant l'index à l'intérieur []

sapam
la source
-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
la source
7
os.getcwd () renvoie le répertoire WORKING actuel du PROCESS, et non le répertoire du fichier en cours d'exécution. Cela peut sembler renvoyer les résultats corrects, mais il existe de nombreux cas où le résultat ne serait pas le répertoire parent du fichier actuel. Il vaut mieux utiliser os.path.dirname ( fichier ) comme suggéré ci-dessus.
samaspin