Obtenir le nom du script actuel en Python

408

J'essaie d'obtenir le nom du script Python en cours d'exécution.

J'ai un script appelé foo.pyet j'aimerais faire quelque chose comme ça afin d'obtenir le nom du script:

print Scriptname
SubniC
la source

Réponses:

621

Vous pouvez utiliser __file__pour obtenir le nom du fichier actuel. Lorsqu'il est utilisé dans le module principal, il s'agit du nom du script qui a été initialement appelé.

Si vous souhaitez omettre la partie répertoire (qui peut être présente), vous pouvez utiliser os.path.basename(__file__).

Sven Marnach
la source
15
Python 3.2: " Exception NameError: NameError("global name '__file__' is not defined",)"
sdaau
20
@sdaau: __file__n'est pas défini dans l'interpréteur interactif, car il n'a pas de sens là-bas. Il est défini par l'implémentation d'importation, donc si vous utilisez un mécanisme d'importation non standard, il peut également ne pas être défini.
Sven Marnach
8
Au moins pour Python 2.7, je crois qu'un import osest requis pour que cela fonctionne. J'ajouterais ceci dans la réponse.
Nick Chammas
14
@ cdunn2001: import oset import os.pathsont complètement équivalents.
Sven Marnach
2
@ sven-marnach: Oh, tu as raison . Je le fais mal depuis des années!
cdunn2001
136
import sys
print sys.argv[0]

Cela s'imprimera foo.pypour python foo.py, dir/foo.pypour python dir/foo.py, etc. C'est le premier argument de python. (Notez qu'après py2exe, ce serait le cas foo.exe.)

Chris Morgan
la source
33
@DenisMalinovsky: définissez "ne fonctionnera pas". Si vous appelez python linkfile.py, où linkfile.pyest un lien symbolique vers realfile.py, sys.argv[0]sera 'linkfile.py', qui peut ou non être ce que vous voulez; c'est certainement ce que j'attends . __file__c'est pareil: ça le sera linkfile.py. Si vous souhaitez rechercher à 'realfile.py'partir de 'linkfile.py', essayez os.path.realpath('linkfile.py').
Chris Morgan
6
+1 parce que c'est (a) un peu plus propre et (b) fonctionnera toujours dans le module (où la variable de fichier serait le fichier de module, pas celui exécuté).
robert
Cette réponse est agréable car elle fonctionne également en mode IDLE. Remarque: pour obtenir uniquement le nom du fichier, vous pouvez écrire os.path.basename (sys.argv [0])
Steven Bluen
Plus important encore, cela ne fonctionne que depuis l'intérieur du fichier principal. Ne l'utilisez pas, utilisez __file__plutôt.
Apollys prend en charge Monica le
QUOI!!! Avez-vous même essayé cela? C'est exactement le contraire qui est vrai. L'interrogateur a demandé le nom du script python en cours d'exécution - pas le fichier python en cours d'exécution. Imaginez que vous disposez d'un script qui, lorsqu'une erreur se produit, imprime le nom du script ainsi que les arguments autorisés. Vous mettez cela dans une fonction, en utilisant l'une de ces 2 techniques. À un moment donné, vous décidez de déplacer la fonction vers une bibliothèque externe. Souhaitez-vous imprimer le nom du script principal en cours d'exécution ou le nom du fichier de bibliothèque en cours d'exécution?
John Deighan
71

Dans un souci d'exhaustivité, j'ai pensé qu'il serait utile de résumer les différents résultats possibles et de fournir des références pour le comportement exact de chacun:

  • __file__est le fichier en cours d'exécution, comme détaillé dans la documentation officielle :

    __file__est le chemin d'accès du fichier à partir duquel le module a été chargé, s'il a été chargé à partir d'un fichier. L' __file__attribut peut être manquant pour certains types de modules, tels que les modules C qui sont liés statiquement à l'interpréteur; pour les modules d'extension chargés dynamiquement à partir d'une bibliothèque partagée, c'est le chemin d'accès du fichier de bibliothèque partagée.

    À partir de Python3.4 , par problème 18416 , __file__est toujours un chemin absolu, sauf si le fichier en cours d'exécution est un script qui a été exécuté directement (pas via l'interpréteur avec l' -moption de ligne de commande) en utilisant un chemin relatif.

  • __main__.__file__(nécessite l'importation __main__) accède simplement à l' __file__attribut susmentionné du module principal , par exemple du script qui a été appelé à partir de la ligne de commande.

  • sys.argv[0](nécessite l'importation sys) est le nom du script qui a été appelé à partir de la ligne de commande, et peut être un chemin absolu, comme détaillé dans la documentation officielle :

    argv[0]est le nom du script (il dépend du système d'exploitation, qu'il s'agisse ou non d'un chemin d'accès complet). Si la commande a été exécutée à l'aide de l' -coption de ligne de commande de l'interpréteur, argv[0]est définie sur la chaîne '-c'. Si aucun nom de script n'a été transmis à l'interpréteur Python, il argv[0]s'agit de la chaîne vide.

    Comme mentionné dans une autre réponse à cette question , les scripts Python qui ont été convertis en programmes exécutables autonomes via des outils tels que py2exe ou PyInstaller peuvent ne pas afficher le résultat souhaité lors de l'utilisation de cette approche (c'est sys.argv[0]-à- dire contenir le nom de l'exécutable plutôt que le nom du fichier Python principal dans cet exécutable).

  • Si aucune des options susmentionnées ne semble fonctionner, probablement en raison d'une opération d'importation irrégulière, le module d'inspection peut s'avérer utile. En particulier, invoquer inspect.getfile(...)sur inspect.currentframe()pourrait fonctionner, bien que ce dernier revienneNone lors de l'exécution dans une implémentation sans cadre de pile Python .


Gérer les liens symboliques

Si le script actuel est un lien symbolique, alors tout ce qui précède retournerait le chemin du lien symbolique plutôt que le chemin du fichier réel et os.path.realpath(...)devrait être invoqué pour extraire ce dernier.


Manipulations supplémentaires qui extraient le nom de fichier réel

os.path.basename(...)peut être invoqué sur l'un des éléments ci-dessus afin d'extraire le nom de fichier réel et os.path.splitext(...)peut être invoqué sur le nom de fichier réel afin de tronquer son suffixe, comme dans os.path.splitext(os.path.basename(...)).

À partir de Python 3.4 , conformément au PEP 428 , la PurePathclasse du pathlibmodule peut également être utilisée sur n'importe lequel des éléments ci-dessus. Plus précisément, pathlib.PurePath(...).nameextrait le nom de fichier réel et pathlib.PurePath(...).stemextrait le nom de fichier réel sans son suffixe.

Yoel
la source
66

Notez que __file__cela donnera le fichier où réside ce code, qui peut être importé et différent du fichier principal en cours d'interprétation. Pour obtenir le fichier principal, le module spécial __main__ peut être utilisé:

import __main__ as main
print(main.__file__)

Notez que cela __main__.__file__fonctionne dans Python 2.7 mais pas dans 3.2, utilisez donc la syntaxe import-as comme ci-dessus pour la rendre portable.

Ambroz Bizjak
la source
Cela fonctionne dans de nombreux cas, mais pas lorsque j'utilise le rPythonpackage à partir de la Rlangue. Ce doit être un cas exceptionnel qui est tout simplement trop difficile à gérer.
Leonid
En effet, le package rPython intègre l'interpréteur python, ce qui signifie qu'il n'y a pas de fichier `` principal '' comme il en existe lorsque python s'exécute de manière autonome (vous trouverez le même comportement à chaque fois que python est incorporé). Il importe en __main__interne, pour être utilisé pour passer des variables entre Ret python, il serait donc relativement facile de le définir __main__.__file__avant d'appeler autre chose, mais je ne suis même pas sûr de ce que serait une valeur appropriée dans ce cas.
Perkins
42

Les réponses ci-dessus sont bonnes. Mais j'ai trouvé cette méthode plus efficace en utilisant les résultats ci-dessus.
Il en résulte que le nom de fichier de script réel n'est pas un chemin.

import sys    
import os    
file_name =  os.path.basename(sys.argv[0])
Manoj Sahu
la source
1
J'aime aussi séparer l'extension, donc j'utilise: os.path.splitext (os.path.basename (sys.argv [0])) [0]
RufusVS
19

Pour les versions modernes de Python (3.4+), Path(__file__).namedevrait être plus idiomatique. Vous Path(__file__).stemdonne également le nom du script sans l' .pyextension.

Emil Melnikov
la source
NameError: le nom 'Path' n'est pas défini
RufusVS
5
Vous devriez d' from pathlib import Pathabord.
Emil Melnikov
"moderne" signifie Python 3.x?
einpoklum
1
@einpoklum a pathlibété introduit dans Python 3.4, il devrait donc fonctionner à partir de Python 3.4.
Andrey Semakin
9

Essaye ça:

print __file__
demas
la source
9

Remarque: Si vous utilisez Python 3+, vous devez utiliser la fonction print () à la place

En supposant que le nom de fichier est foo.py, l'extrait ci-dessous

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

ou

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

Comme pour les autres extensions avec plus de caractères, par exemple le nom de fichier foo.pypy

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

Si vous souhaitez extraire d'un chemin absolu

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

affichera foo

xtonousou
la source
1
sys.argv [0] [: - 3] ferait l'affaire
kon psych
@konpsych c'est plus élégant
xtonousou
Il y a une grande différence entre __file__et sys.argv[0], voir stackoverflow.com/questions/5851588/…
Maksym Ganenko
8

Le premier argument dans sys sera le nom du fichier actuel, donc cela fonctionnera

   import sys
   print sys.argv[0] # will print the file name
Charlie OConor
la source
7

Si vous effectuez une importation inhabituelle (par exemple, c'est un fichier d'options), essayez:

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

Notez que cela renverra le chemin absolu du fichier.

Gajendra D Ambi
la source
3

nous pouvons essayer ceci pour obtenir le nom du script actuel sans extension.

import os

script_name = os.path.splitext(os.path.basename(__file__))[0]
Krishn Singh
la source
2

Étant donné que l'OP a demandé le nom du fichier de script actuel, je préférerais

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

toutes ces réponses sont excellentes, mais ont quelques problèmes que vous pourriez ne pas voir au premier coup d'œil.

permet de définir ce que nous voulons - nous voulons le nom du script qui a été exécuté, pas le nom du module actuel - __file__ne fonctionnera donc que s'il est utilisé dans le script exécuté, pas dans un module importé. sys.argvest également discutable - et si votre programme était appelé par pytest? ou coureur pydoc? ou si elle a été appelée par uwsgi?

et - il y a une troisième méthode pour obtenir le nom du script, je n'ai pas vu dans les réponses - Vous pouvez inspecter la pile.

Un autre problème est que vous (ou un autre programme) pouvez altérer sys.argvet__main__.__file__ - il peut être présent, il se peut que ce ne soit pas le cas. Il peut être valide ou non. Vous pouvez au moins vérifier si le script (le résultat souhaité) existe!

ma bibliothèque bitranox / lib_programname sur github fait exactement cela:

  • vérifier s'il __main__est présent
  • vérifier s'il __main__.__file__est présent
  • donne __main__.__file__un résultat valide (ce script existe-t-il?)
  • sinon: vérifiez sys.argv:
  • y a-t-il pytest, docrunner, etc. dans le sys.argv? -> si oui, ignorez ça
  • pouvons-nous obtenir un résultat valide ici?
  • sinon: inspectez la pile et obtenez éventuellement le résultat
  • si la pile ne donne pas non plus de résultat valide, lancez une exception.

par là, ma solution fonctionne à ce jour avec setup.py test, uwsgi, pytest, pycharm pytest, pycharm docrunner (doctest), dreampie,eclipse

il y a aussi un bel article de blog sur ce problème de Dough Hellman, "Déterminer le nom d'un processus à partir de Python"

bitranox
la source
0

Ma solution rapide et sale:

__file__.split('/')[-1:][0]
E.Big
la source
2
Meilleure utilisation os.pathpour diviser les noms de fichiers
Maksym Ganenko
0

Depuis Python 3.5, vous pouvez simplement faire:

from pathlib import Path
Path(__file__).stem

Voir plus ici: https://docs.python.org/3.5/library/pathlib.html#pathlib.PurePath.stem

Par exemple, j'ai un fichier sous mon répertoire utilisateur nommé test.pyavec ceci à l'intérieur:

from pathlib import Path

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

l'exécution de ces sorties:

>>> python3.6 test.py
test
test.py
elad silver
la source