¿Cómo obtengo la ruta del archivo ejecutado actual en Python?

Esto puede parecer una pregunta de novato, pero no lo es. Algunos enfoques comunes no funcionan en todos los casos:

sys.argv [0]

Esto significa usar path = os.path.abspath(os.path.dirname(sys.argv[0])) , pero esto no funciona si está ejecutando desde otro script de Python en otro directorio, y esto puede suceder en la vida real .

__expediente__

Esto significa usar path = os.path.abspath(os.path.dirname(__file__)) , pero encontré que esto no funciona:

  • py2exe no tiene un atributo __file__ , pero hay una solución alternativa
  • Cuando se ejecuta desde IDLE con execute() no hay ningún atributo __file__
  • OS X 10.6 donde obtengo NameError: global name '__file__' is not defined

Preguntas relacionadas con respuestas incompletas:

  • Python – Encuentre la ruta al archivo que se está ejecutando
  • La ruta al archivo actual depende de cómo ejecuto el progtwig
  • ¿Cómo saber la ruta del script en ejecución en Python?
  • Cambiar el directorio al directorio de un script de Python

Estoy buscando una solución genérica , una que funcione en todos los casos de uso anteriores.

Actualizar

Aquí está el resultado de un testcase:

Salida de python a.py (en Windows)

 a.py: __file__= a.py a.py: os.getcwd()= C:\zzz b.py: sys.argv[0]= a.py b.py: __file__= a.py b.py: os.getcwd()= C:\zzz 

a.py

 #! /usr/bin/env python import os, sys print "a.py: sys.argv[0]=", sys.argv[0] print "a.py: __file__=", __file__ print "a.py: os.getcwd()=", os.getcwd() print execfile("subdir/b.py") 

subdir / b.py

 #! /usr/bin/env python import os, sys print "b.py: sys.argv[0]=", sys.argv[0] print "b.py: __file__=", __file__ print "b.py: os.getcwd()=", os.getcwd() print 

árbol

 C:. | a.py \---subdir b.py 

No se puede determinar directamente la ubicación del script principal que se está ejecutando. Después de todo, a veces el script no viene de un archivo en absoluto. Por ejemplo, podría provenir del intérprete interactivo o el código generado dinámicamente almacenado solo en la memoria.

Sin embargo, puede determinar de manera confiable la ubicación de un módulo, ya que los módulos siempre se cargan desde un archivo. Si crea un módulo con el siguiente código y lo coloca en el mismo directorio que su script principal, entonces el script principal puede importar el módulo y usarlo para ubicarse.

some_path / module_locator.py:

 def we_are_frozen(): # All of the modules are built-in to the interpreter, eg, by py2exe return hasattr(sys, "frozen") def module_path(): encoding = sys.getfilesystemencoding() if we_are_frozen(): return os.path.dirname(unicode(sys.executable, encoding)) return os.path.dirname(unicode(__file__, encoding)) 

some_path / main.py:

 import module_locator my_path = module_locator.module_path() 

Si tiene varios scripts principales en diferentes directorios, puede necesitar más de una copia de module_locator.

Por supuesto, si su script principal está cargado por alguna otra herramienta que no le permite importar módulos que se ubican junto con su script, entonces no tendrá suerte. En casos como ese, la información que está buscando simplemente no existe en ningún lugar de su progtwig. Su mejor apuesta sería presentar un error a los autores de la herramienta.

Primero, necesitas importar desde inspect y os

 from inspect import getsourcefile from os.path import abspath 

A continuación, donde quiera que quiera encontrar el archivo de origen, solo use

 abspath(getsourcefile(lambda:0)) 

Me estaba topando con un problema similar, y creo que esto podría resolver el problema:

 def module_path(local_function): ''' returns the module path without the use of __file__. Requires a function defined locally in the module. from http://stackoverflow.com/questions/729583/getting-file-path-of-imported-module''' return os.path.abspath(inspect.getsourcefile(local_function)) 

Funciona para scripts regulares y en inactivo. ¡Todo lo que puedo decir es probarlo para otros!

Mi uso típico:

 from toolbox import module_path def main(): pass # Do stuff global __modpath__ __modpath__ = module_path(main) 

Ahora uso __modpath__ en lugar de __file__.

La respuesta corta es que no hay una forma garantizada de obtener la información que desea , sin embargo, hay heurísticas que funcionan casi siempre en la práctica. Puedes ver ¿Cómo encuentro la ubicación del ejecutable en C? . Discute el problema desde el punto de vista de C, pero las soluciones propuestas se transcriben fácilmente en Python.

Esta solución es robusta incluso en ejecutables.

 import inspect, os.path filename = inspect.getframeinfo(inspect.currentframe()).filename path = os.path.dirname(os.path.abspath(filename)) 

Vea mi respuesta a la pregunta Importación de módulos de la carpeta principal para obtener información relacionada, incluyendo por qué mi respuesta no usa la variable __file__ no __file__ . Esta solución simple debe ser compatible con diferentes sistemas operativos, ya que los módulos os e inspect forman parte de Python.

Primero, necesita importar partes de los módulos insp y os .

 from inspect import getsourcefile from os.path import abspath 

A continuación, use la siguiente línea en cualquier otro lugar que necesite en su código de Python:

 abspath(getsourcefile(lambda:0)) 

Cómo funciona:

Desde el módulo incorporado os (descripción a continuación), se abspath herramienta abspath .

Rutinas del sistema operativo para Mac, NT o Posix, según el sistema en el que estemos.

Luego se getsourcefile (descripción a continuación) desde el módulo incorporado inspect .

Obtenga información útil de los objetos vivos de Python.

  • abspath(path) devuelve la versión absoluta / completa de una ruta de archivo
  • getsourcefile(lambda:0) alguna manera obtiene el archivo de origen interno del objeto de función lambda, por lo que devuelve '' en el shell de Python o devuelve la ruta del archivo del código de Python que se está ejecutando actualmente.

El uso de abspath en el resultado de getsourcefile(lambda:0) debe asegurarse de que la ruta del archivo generado sea la ruta completa del archivo Python.
Esta solución explicada se basó originalmente en el código de la respuesta en ¿Cómo obtengo la ruta del archivo ejecutado actual en Python? .

Usted simplemente ha llamado:

 path = os.path.abspath(os.path.dirname(sys.argv[0])) 

en lugar de:

 path = os.path.dirname(os.path.abspath(sys.argv[0])) 

abspath() le da la ruta absoluta de sys.argv[0] (el nombre de archivo en el que se encuentra su código) y dirname() devuelve la ruta del directorio sin el nombre de archivo.

Esto debería hacer el truco de una manera multiplataforma (siempre y cuando no estés usando el intérprete o algo así):

 import os, sys non_symbolic=os.path.realpath(sys.argv[0]) program_filepath=os.path.join(sys.path[0], os.path.basename(non_symbolic)) 

sys.path[0] es el directorio en el que se encuentra su script de llamada (el primer lugar en el que busca los módulos que utilizará ese script). Podemos quitar el nombre del archivo al final de sys.argv[0] (que es lo que hice con os.path.basename ). os.path.join solo los une de forma multiplataforma. os.path.realpath solo se asegura de que obtengamos algún enlace simbólico con nombres diferentes a los del script en sí mismo y que aún obtengamos el nombre real del script.

No tengo una Mac; así que, no he probado esto en uno. Por favor, hágame saber si funciona, como parece que debería. Probé esto en Linux (Xubuntu) con Python 3.4. Tenga en cuenta que muchas soluciones para este problema no funcionan en Mac (ya que he oído decir que __file__ no está presente en Mac).

Tenga en cuenta que si su script es un enlace simbólico, le dará la ruta del archivo al que se vincula (y no la ruta del enlace simbólico).

Puedes usar la Path del módulo pathlib :

 from pathlib import Path # ... Path(__file__) 

Puede utilizar la llamada a los parent para ir más lejos en la ruta:

 Path(__file__).parent 

Simplemente agregue lo siguiente:

 from sys import * path_to_current_file = sys.argv[0] print(path_to_current_file) 

O:

 from sys import * print(sys.argv[0]) 

Si el código proviene de un archivo, puede obtener su nombre completo

 sys._getframe().f_code.co_filename 

También puede recuperar el nombre de la función como f_code.co_name

Mi solución es:

 import os print(os.path.join(os.getcwd(), __file__)) 
 import os current_file_path=os.path.dirname(os.path.realpath('__file__'))