Obtener el nombre del script actual en Python

408

Estoy tratando de obtener el nombre del script de Python que se está ejecutando actualmente.

Tengo un script llamado foo.pyy me gustaría hacer algo como esto para obtener el nombre del script:

print Scriptname
SubniC
fuente

Respuestas:

621

Puede usar __file__para obtener el nombre del archivo actual. Cuando se usa en el módulo principal, este es el nombre del script que se invocó originalmente.

Si desea omitir la parte del directorio (que podría estar presente), puede usar os.path.basename(__file__).

Sven Marnach
fuente
15
Python 3.2: " Exception NameError: NameError("global name '__file__' is not defined",)"
sdaau
20
@sdaau: __file__no está definido en el intérprete interactivo, porque no tiene sentido allí. Lo establece la implementación de importación, por lo que si usa un mecanismo de importación no estándar, también podría estar desarmado.
Sven Marnach
8
Al menos para Python 2.7, creo que import oses necesario para que esto funcione. Añadiría esto a la respuesta.
Nick Chammas
14
@ cdunn2001: import osy import os.pathson completamente equivalentes.
Sven Marnach
2
@ sven-marnach: Oh, tienes razón . ¡Lo he estado haciendo mal durante años!
cdunn2001
136
import sys
print sys.argv[0]

Esto imprimirá foo.pypara python foo.py, dir/foo.pypara python dir/foo.py, etc. Es el primer argumento para python. (Tenga en cuenta que después de py2exe sería foo.exe).

Chris Morgan
fuente
33
@DenisMalinovsky: defina "no funcionará". Si llama python linkfile.py, donde linkfile.pyes un enlace simbólico realfile.py, sys.argv[0]será 'linkfile.py', lo que puede o no ser lo que desea; Ciertamente es lo que espero . __file__es lo mismo: lo será linkfile.py. Si desea buscar 'realfile.py'desde 'linkfile.py', intente os.path.realpath('linkfile.py').
Chris Morgan
66
+1 porque es (a) un poco más ordenado y (b) seguirá funcionando en el módulo (donde la variable del archivo sería el archivo del módulo, no el ejecutado).
robert
Esta respuesta es buena porque también funciona en IDLE. Como nota, para obtener solo el nombre del archivo, puede escribir os.path.basename (sys.argv [0])
Steven Bluen
Más importante aún, esto no funciona excepto desde el interior del archivo principal. No use esto, use __file__en su lugar.
Apollys apoya a Monica el
¡¡¡QUÉ!!! ¿Intentaste esto? Exactamente lo contrario es cierto. El interlocutor solicitó el nombre del script de Python que se está ejecutando, no el archivo de Python que se está ejecutando actualmente. Imagine que tiene un script que, cuando ocurre un error, imprime el nombre del script junto con los argumentos permitidos. Pones eso en una función, usando una de estas 2 técnicas. En algún momento, decide mover la función a una biblioteca externa. ¿Desea imprimir el nombre del script principal en ejecución o el nombre del archivo de biblioteca que se está ejecutando?
John Deighan
71

Para completar, pensé que valdría la pena resumir los diversos resultados posibles y proporcionar referencias para el comportamiento exacto de cada uno:

  • __file__es el archivo actualmente en ejecución, como se detalla en la documentación oficial :

    __file__es la ruta del archivo desde el que se cargó el módulo, si se cargó desde un archivo. El __file__atributo puede faltar para ciertos tipos de módulos, como C módulos que están vinculados estáticamente al intérprete; para módulos de extensión cargados dinámicamente desde una biblioteca compartida, es la ruta del archivo de la biblioteca compartida.

    Desde Python3.4 en adelante, por número 18416 , __file__siempre es una ruta absoluta, a menos que el archivo actualmente en ejecución sea un script que se haya ejecutado directamente (no a través del intérprete con el-m opción de línea de comando) usando una ruta relativa.

  • __main__.__file__(requiere importación __main__) simplemente accede al __file__atributo mencionado anteriormente del módulo principal , por ejemplo, del script que se invocó desde la línea de comandos.

  • sys.argv[0](requiere importación sys) es el nombre del script que se invocó desde la línea de comando, y podría ser una ruta absoluta, como se detalla en la documentación oficial :

    argv[0]es el nombre del script (depende del sistema operativo si se trata de un nombre de ruta completo o no). Si el comando se ejecutó utilizando la -copción de línea de comando para el intérprete, argv[0]se establece en la cadena '-c'. Si no se pasó ningún nombre de script al intérprete de Python, argv[0]es la cadena vacía.

    Como se mencionó en otra respuesta a esta pregunta , los scripts de Python que se convirtieron en programas ejecutables independientes a través de herramientas como py2exe o PyInstaller podrían no mostrar el resultado deseado al usar este enfoque (es decir sys.argv[0], contendrían el nombre del ejecutable en lugar del nombre de la Python principal archivo dentro de ese ejecutable).

  • Si ninguna de las opciones mencionadas parece funcionar, probablemente debido a una operación de importación irregular, el módulo de inspección podría resultar útil. En particular, invocar inspect.getfile(...)a inspect.currentframe()podría funcionar, aunque este último volveríaNone cuando se ejecute en una implementación sin marco de pila de Python .


Manejo de enlaces simbólicos

Si el script actual es un enlace simbólico, todo lo anterior devolvería la ruta del enlace simbólico en lugar de la ruta del archivo real y os.path.realpath(...)debería invocarse para extraer este último.


Manipulaciones adicionales que extraen el nombre real del archivo

os.path.basename(...)se puede invocar en cualquiera de los anteriores para extraer el nombre real del archivo y os.path.splitext(...)se puede invocar en el nombre real del archivo para truncar su sufijo, como en os.path.splitext(os.path.basename(...)).

Desde Python 3.4 en adelante, según PEP 428 , la PurePathclase del pathlibmódulo también se puede usar en cualquiera de los anteriores. Específicamente, pathlib.PurePath(...).nameextrae el nombre real del archivo y pathlib.PurePath(...).stemextrae el nombre real del archivo sin su sufijo.

Yoel
fuente
66

Tenga en cuenta que __file__le dará al archivo donde reside este código, que puede importarse y ser diferente del archivo principal que se está interpretando. Para obtener el archivo principal, se puede usar el módulo especial __main__ :

import __main__ as main
print(main.__file__)

Tenga __main__.__file__en cuenta que funciona en Python 2.7 pero no en 3.2, por lo tanto, use la sintaxis import-as como arriba para hacerlo portátil.

Ambroz Bizjak
fuente
Esto funciona en muchos casos, pero no cuando estoy usando el rPythonpaquete desde el Ridioma. Ese debe ser un caso excepcional que es demasiado difícil de manejar.
Leonid
De hecho, el paquete rPython incorpora el intérprete de python, lo que significa que no hay un archivo 'principal' como el que existe cuando python se ejecuta por sí solo (encontrará el mismo comportamiento cada vez que se incruste python). Importa __main__internamente, para usar al pasar variables entre Ry python, por lo que sería relativamente fácil configurarlo __main__.__file__antes de llamar a cualquier otra cosa, pero ni siquiera estoy seguro de cuál sería un valor apropiado en este caso.
Perkins
42

Las respuestas anteriores son buenas. Pero este método me pareció más eficiente utilizando los resultados anteriores.
Esto da como resultado que el nombre real del archivo de script no es una ruta.

import sys    
import os    
file_name =  os.path.basename(sys.argv[0])
Manoj Sahu
fuente
1
También me gusta dividir la extensión, así que uso: os.path.splitext (os.path.basename (sys.argv [0])) [0]
RufusVS
19

Para las versiones modernas de Python (3.4+), Path(__file__).namedebería ser más idiomático. Además, Path(__file__).stemle da el nombre del script sin la .pyextensión.

Emil Melnikov
fuente
NameError: el nombre 'Path' no está definido
RufusVS
55
Deberías from pathlib import Pathprimero.
Emil Melnikov
"moderno" significa Python 3.x?
Einpoklum
1
@einpoklum pathlibse introdujo en Python 3.4, por lo que debería funcionar a partir de Python 3.4.
Andrey Semakin
9

Prueba esto:

print __file__
demas
fuente
9

Nota: Si está usando Python 3+, entonces debería usar la función print () en su lugar

Suponiendo que el nombre del archivo es foo.py, el fragmento a continuación

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

o

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

En cuanto a otras extensiones con más caracteres, por ejemplo, el nombre del archivo foo.pypy

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

Si quieres extraer de una ruta absoluta

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

saldrá foo

xtonousou
fuente
1
sys.argv [0] [: - 3] haría
kon psych
@konpsych que es más elegante
xtonousou
Hay una gran diferencia entre __file__y sys.argv[0], consulte stackoverflow.com/questions/5851588/…
Maksym Ganenko
8

El primer argumento en sys será el nombre del archivo actual, por lo que esto funcionará

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

Si está haciendo una importación inusual (por ejemplo, es un archivo de opciones), intente:

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

Tenga en cuenta que esto devolverá la ruta absoluta al archivo.

Gajendra D Ambi
fuente
3

podemos intentar esto para obtener el nombre del script actual sin extensión.

import os

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

Como el OP solicitó el nombre del archivo de script actual, preferiría

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

todas esas respuestas son geniales, pero tienen algunos problemas Es posible que no veas a primera vista.

definamos lo que queremos: queremos el nombre del script que se ejecutó, no el nombre del módulo actual, por __file__lo que solo funcionará si se usa en el script ejecutado, no en un módulo importado. sys.argvtambién es cuestionable: ¿qué pasa si su programa fue llamado por pytest? o corredor pydoc? o si fue llamado por uwsgi?

y - hay un tercer método para obtener el nombre del script, no lo he visto en las respuestas - Puedes inspeccionar la pila.

Otro problema es que usted (o algún otro programa) puede manipular sys.argvy__main__.__file__ puede estar presente, puede que no. Puede ser válido o no. ¡Al menos puedes comprobar si el script (el resultado deseado) existe!

mi biblioteca bitranox / lib_programname en github hace exactamente eso:

  • verificar si __main__está presente
  • verificar si __main__.__file__está presente
  • da __main__.__file__un resultado válido (¿existe ese script?)
  • si no: compruebe sys.argv:
  • ¿hay pytest, docrunner, etc. en sys.argv? -> si es así, ignora eso
  • ¿Podemos obtener un resultado válido aquí?
  • si no: inspeccione la pila y obtenga el resultado de allí posiblemente
  • si también la pila no da un resultado válido, entonces lanza una Excepción.

por ese camino, mi solución está trabajando hasta ahora con setup.py test, uwsgi, pytest, pycharm pytest, pycharm docrunner (doctest), dreampie,eclipse

también hay un buen artículo de blog sobre ese problema de Dough Hellman, "Determinando el nombre de un proceso desde Python"

bitranox
fuente
0

Mi solución rápida y sucia:

__file__.split('/')[-1:][0]
E.Big
fuente
2
Mejor uso os.pathpara dividir nombres de archivos
Maksym Ganenko
0

A partir de Python 3.5, simplemente puede hacer:

from pathlib import Path
Path(__file__).stem

Ver más aquí: https://docs.python.org/3.5/library/pathlib.html#pathlib.PurePath.stem

Por ejemplo, tengo un archivo en mi directorio de usuarios test.pycon este nombre :

from pathlib import Path

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

ejecutando estas salidas:

>>> python3.6 test.py
test
test.py
elad plata
fuente