¿Cómo obtengo la ruta y el nombre del archivo que se está ejecutando actualmente?

482

Tengo scripts que llaman a otros archivos de script pero necesito obtener la ruta del archivo que se está ejecutando actualmente en el proceso.

Por ejemplo, digamos que tengo tres archivos. Usando execfile :

  • script_1.pyllamadas script_2.py.
  • A su vez, script_2.pyllamadas script_3.py.

¿Cómo puedo obtener el nombre y la ruta del archivo script_3.py, desde el código internoscript_3.py , sin tener que pasar esa información como argumentos script_2.py?

(La ejecución os.getcwd()devuelve la ruta de archivo del script inicial original, no la del archivo actual).

Rayo
fuente
2
os.path.realpath ( archivo )
Girish Gupta

Respuestas:

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
fuente
11
CUIDADO: Esta llamada no da el mismo resultado con diferentes entornos. Considere aceptar la respuesta de Usagi a continuación: stackoverflow.com/a/6628348/851398
faraday
3
@faraday: ¿Podrías dar un ejemplo? He respondido preguntas similares usandoinspect.getabsfile() y funcionó para todos los casos que he probado.
jfs
1
¿De hecho @Usagi responde mejor?
Dror
44
nah user13993 lo clavó mucho mejor
osirisgothra
66
user13993 de hecho lo clavó. Debería seros.path.realpath(__file__)
uchuugaka
566
__file__

como han dicho otros. También puede usar os.path.realpath para eliminar enlaces simbólicos:

import os

os.path.realpath(__file__)
usuario13993
fuente
14
Hay que tener cuidado con este enfoque porque a veces __file__devuelve 'script_name.py', y otras veces 'script_name.pyc'. Entonces la salida no es estable.
Mechatroner
27
Pero dado que solo estamos usando la ruta de este archivo es irrelevante.
Uwe Koloska
55
esto es extraño: cuando se ejecuta desde la línea de comandos "__file__"entre comillas (como cadena) se obtiene el directorio desde el que se ejecuta cmd, pero __file__ (sin comillas se obtiene la ruta al archivo de origen ... por qué es eso
muon
77
@muon no se verifica si existe una cadena de nombre de archivo pasada, y dado que las rutas de los archivos son relativas al cwd, eso es lo que la os.path.realpathfunción supone que es la dirparte de la ruta. os.path.dirname(os.path.realpath(__file__))devuelve el directorio con el archivo os.path.dirname(os.path.realpath("__file__"))devuelve cwd. os.path.dirname(os.path.realpath("here_be_dragons"))También devuelve cwd.
Jamie Bull
86

Actualización 2018-11-28:

Aquí hay un resumen de los experimentos con Python 2 y 3. Con

main.py: ejecuta foo.py
foo.py: ejecuta lib / bar.py
lib / bar.py: imprime expresiones de ruta de archivo

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

Para Python 2, puede ser más claro cambiar a paquetes para poder usarlos from lib import bar, simplemente agregue __init__.pyarchivos vacíos a las dos carpetas.

Para Python 3, execfileno existe; la alternativa más cercana es exec(open(<filename>).read()), aunque esto afecta los marcos de la pila. Es más fácil de usar import fooy import lib.barno se __init__.pynecesitan archivos.

Consulte también Diferencia entre importación y archivo de ejecución


Respuesta original

Aquí hay un experimento basado en las respuestas de este hilo, con Python 2.7.10 en Windows.

Los basados ​​en la pila son los únicos que parecen dar resultados confiables. Los dos últimos tienen la sintaxis más corta , es decir:

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

¡Aquí se agrega a sys como funciones! Crédito a @Usagi y @pablog

Basado en los siguientes tres archivos, y ejecutando main.py desde su carpeta con python main.py(también probé archivos ejecutables con rutas absolutas y llamadas desde una carpeta separada).

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
fuente
72

Creo que esto es más limpio:

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

y obtiene la misma información que:

print inspect.getfile(inspect.currentframe())

Donde [0] es el marco actual en la pila (parte superior de la pila) y [1] es para el nombre del archivo, aumente para ir hacia atrás en la pila, es decir

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

sería el nombre del archivo del script que llamó al marco actual. Además, el uso de [-1] lo llevará al final de la pila, el script de llamada original.

Usagi
fuente
44
No recomiendo confiar en la posición dentro de la tupla. No está claro en absoluto qué datos está tratando de obtener al leer el código.
jpmc26
55
inspect.getfile()devuelve el __file__atributo si se pasa un objeto de módulo. inspect.currentframe()devuelve el módulo Ergo, esta es una forma costosa de decir __file__.
Martijn Pieters
inspect.stack()es una función bastante costosa, más que simplemente inspect.currentframe(), y también llama inspect.getfile()a un objeto de módulo.
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
fuente
1
Acabo de probar el comentario de @Pat Notz. Creo que podrías obtener el nombre del archivo __file__.
hlin117
En Python3, os.path.dirnamele dará la ruta relativa desde donde está ejecutando el script. por ejemplo, en python ../../test.pyla os.path.dirnamevoluntad ../../y no en la ruta absoluta al guión. Estaba buscando abspath pero eliminaba el nombre del script. El primer elemento de sys.path aparentemente es la respuesta sys.path[0].
Aerijman
37

Las sugerencias marcadas como mejores son todas verdaderas si su secuencia de comandos consta de un solo archivo.

Si desea averiguar el nombre del ejecutable (es decir, el archivo raíz pasado al intérprete de Python para el programa actual) desde un archivo que puede importarse como un módulo, debe hacerlo (supongamos que está en un archivo llamado foo.py ):

import inspect

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

Porque lo último ( [-1]) en la pila es lo primero que entró (las pilas son estructuras de datos LIFO / FILO).

Luego, en el archivo bar.py, si import fooimprime bar.py , en lugar de foo.py , que sería el valor de todos estos:

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

fuente
Funciona bien pero no para la prueba de unidad en eclipse, obtuve /home/user/Softwares/eclipse/plugins/org.python.pydev_4.5.5.201603221110/pysrc
hayj
2
Esta es una forma costosa de deletrear sys.modules['__main__'].__file__, de verdad.
Martijn Pieters
14
import os
print os.path.basename(__file__)

esto solo nos dará el nombre del archivo. es decir, si abspath del archivo es c: \ abcd \ abc.py, la segunda línea imprimirá abc.py

vishal ekhe
fuente
14

No está del todo claro qué quiere decir con "la ruta del archivo que se está ejecutando actualmente en el proceso". sys.argv[0]generalmente contiene la ubicación del script invocado por el intérprete de Python. Consulte la documentación del sistema para obtener más detalles.

Como han señalado @Tim y @Pat Notz, el atributo __file__ proporciona acceso a

el archivo desde el que se cargó el módulo, si se cargó desde un archivo

Blair Conrad
fuente
1
"print os.path.abspath ( file )" y "print inspect.getfile (inspect.currentframe ())" no funcionan cuando pasamos el programa python a un win32 exe. ¡Solo sys.argv [0] funciona! :) pero solo obtienes el nombre!
aF.
11

Tengo un script que debe funcionar en un entorno Windows. Este código cortado es con lo que he terminado:

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

Es una decisión bastante hacky. Pero no requiere bibliotecas externas y es lo más importante en mi caso.

Garmoncheg
fuente
1
Tuve que "importar os, sys" para esto, pero hasta ahora es la mejor respuesta que en realidad devuelve solo la ruta sin un nombre de archivo al final de la cadena.
emmagras
10

Prueba esto,

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

No es necesario inspeccionar ni ninguna otra biblioteca.

Esto funcionó para mí cuando tuve que importar un script (desde un directorio diferente al script ejecutado), que utilizaba un archivo de configuración que residía en la misma carpeta que el script importado.

Kwuite
fuente
Esto no producirá la respuesta deseada si el directorio de trabajo actual (os.getcwd) es diferente del directorio en el que se encuentra el archivo.
Iron Pillow
2
¿Cómo es eso? Funciona bien para mí en este caso. Me sale el directorio en el que se encuentra el archivo.
Michael Mior
@IronPillow tal vez esta respuesta te ayudará con lo que necesitas. stackoverflow.com/a/41546830/3123191
Kwuite
6
import sys

print sys.path[0]

esto imprimiría la ruta del script que se está ejecutando actualmente

appusajeev
fuente
2
sys.path [0] es muy útil, pero proporciona la ruta de script1, no script3 como se solicitó
James
Al menos en OS X, con 2.7, no creo que esto haga nada confiable. Funciona si se ejecuta directamente el mismo archivo. No funciona desde la réplica, especialmente de un huevo importado
uchuugaka
5

Creo que __file__ suena como si también quisieras revisar el módulo de inspección .

Pat Notz
fuente
Ahhh ... execfile es complicado. Vea mi otra publicación sobre el uso del módulo de inspección.
Pat Notz
4

Puedes usar 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
fuente
4

Dado que Python 3 es bastante convencional, quería incluir una pathlibrespuesta, ya que creo que probablemente ahora sea una mejor herramienta para acceder a la información de archivos y rutas.

from pathlib import Path

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

Si está buscando el directorio del archivo actual, es tan fácil como agregar .parenta la Path()declaración:

current_path: Path = Path(__file__).parent.resolve()
Doug
fuente
3
import sys
print sys.argv[0]
WBAR
fuente
10
Desafortunadamente, esto solo funciona si se llamó al script con su ruta completa, porque solo devuelve el "primer argumento" en la línea de comando, que es la llamada al script.
cregox
2

Esto debería funcionar:

import os,sys
filename=os.path.basename(os.path.realpath(sys.argv[0]))
dirname=os.path.dirname(os.path.realpath(sys.argv[0]))
Jahid
fuente
2
print(__file__)
print(__import__("pathlib").Path(__file__).parent)
BaiJiFeiLong
fuente
44
Las respuestas de solo código se desaconsejan. Agregue alguna explicación sobre cómo esto resuelve el problema o cómo difiere de las respuestas existentes. De la opinión
Nick
1

Para obtener el directorio del script de ejecución

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

Siempre he usado la función os del directorio de trabajo actual, o CWD. Esto es parte de la biblioteca estándar y es muy fácil de implementar. Aquí hay un ejemplo:

    import os
    base_directory = os.getcwd()
Ethan J.
fuente
1
¿Podría modificar su respuesta para que se aplique a la pregunta planteada? Esta respuesta no se aplica a la pregunta "¿Cómo obtengo la ruta y el nombre del archivo que se está ejecutando actualmente? "
Marco
1
Esto proporciona la ruta desde donde ejecutó el comando python. Por lo tanto, parece funcionar cuando ejecuta el python script.pycomando en la misma carpeta que ya está, cuando en realidad es lo mismo que ejecutar pwden Linux.
George
0

Utilicé el enfoque con __file__
os.path.abspath(__file__)
pero hay un pequeño truco, devuelve el archivo .py cuando se ejecuta el código la primera vez, las siguientes ejecuciones dan el nombre del archivo * .pyc,
así que me quedé con:
inspect.getfile(inspect.currentframe())
o
sys._getframe().f_code.co_filename

mik80
fuente
0

Escribí una función que tiene en cuenta el eclipse depurador y unittest . Devuelve la carpeta del primer script que ejecutas. Opcionalmente, puede especificar el __file__ var, pero lo principal es que no tiene que compartir esta variable en toda su jerarquía de llamadas .

Tal vez pueda manejar otros casos particulares que no vi, pero para mí está bien.

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
fuente
0

Para mantener la coherencia de la migración entre plataformas (macOS / Windows / Linux), intente:

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

Qiao Zhang
fuente
2
Esto está mal. Esto le proporciona la ruta actual, pero no la ruta del archivo actual.
Charles Plager
0

La forma más simple es:

en script_1.py:

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

en script_2.py:

sys.argv[0]

PD: Lo he intentado execfile, pero dado que lee script_2.py como una cadena, sys.argv[0]regresó <string>.

Lucas Azevedo
fuente
0

Esto es lo que uso para poder lanzar mi código en cualquier lugar sin problemas. __name__siempre se define, pero __file__solo se define cuando el código se ejecuta como un archivo (por ejemplo, no en IDLE / iPython).

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

Alternativamente, esto se puede escribir como:

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

La mayoría de estas respuestas fueron escritas en Python versión 2.xo anterior. En Python 3.x, la sintaxis de la función de impresión ha cambiado para requerir paréntesis, es decir, print ().

Entonces, esta respuesta de puntaje anterior del usuario 13993 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

Se convierte 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
usuario3339488
fuente
-3

si solo quieres el nombre del archivo ./o .pypuedes probar esto

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

file_name imprimirá el script de prueba que puede generar lo que quiera cambiando el índice dentro de []

sapam
fuente
-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
fuente
77
os.getcwd () devuelve el directorio de TRABAJO actual del PROCESO, no el directorio del archivo que se está ejecutando actualmente. Puede parecer que esto devuelve los resultados correctos, pero hay muchos casos en los que el resultado no sería el directorio principal del archivo actual. Mucho mejor usar os.path.dirname ( archivo ) como se sugirió anteriormente.
samaspin