¿Cómo recuperar la ruta de un módulo?

Resuelto Cheery asked hace 15 años • 26 respuestas

Quiero detectar si el módulo ha cambiado. Ahora, usar inotify es simple, solo necesita saber el directorio del que desea recibir notificaciones.

¿Cómo recupero la ruta de un módulo en Python?

Cheery avatar Oct 30 '08 00:10 Cheery
Aceptado
import a_module
print(a_module.__file__)

De hecho, le dará la ruta al archivo .pyc que se cargó, al menos en Mac OS X. Así que supongo que puede hacer:

import os
path = os.path.abspath(a_module.__file__)

También puedes probar:

path = os.path.dirname(a_module.__file__)

Para obtener el directorio del módulo.

orestis avatar Oct 29 '2008 23:10 orestis

Hay inspectun módulo en Python.

Documentación oficial

El módulo de inspección proporciona varias funciones útiles para ayudar a obtener información sobre objetos activos, como módulos, clases, métodos, funciones, rastreos, objetos de marco y objetos de código. Por ejemplo, puede ayudarle a examinar el contenido de una clase, recuperar el código fuente de un método, extraer y formatear la lista de argumentos de una función u obtener toda la información que necesita para mostrar un rastreo detallado.

Ejemplo:

>>> import os
>>> import inspect
>>> inspect.getfile(os)
'/usr/lib64/python2.7/os.pyc'
>>> inspect.getfile(inspect)
'/usr/lib64/python2.7/inspect.pyc'
>>> os.path.dirname(inspect.getfile(inspect))
'/usr/lib64/python2.7'
Tomas Tomecek avatar Aug 28 '2012 07:08 Tomas Tomecek

Como han dicho las otras respuestas, la mejor manera de hacerlo es __file__(se demuestra nuevamente a continuación). Sin embargo, hay una advertencia importante: __file__NO existe si ejecuta el módulo por sí solo (es decir, como __main__).

Por ejemplo, digamos que tiene dos archivos (ambos están en su PYTHONPATH):

#/path1/foo.py
import bar
print(bar.__file__)

y

#/path2/bar.py
import os
print(os.getcwd())
print(__file__)

Ejecutar foo.py dará el resultado:

/path1        # "import bar" causes the line "print(os.getcwd())" to run
/path2/bar.py # then "print(__file__)" runs
/path2/bar.py # then the import statement finishes and "print(bar.__file__)" runs

SIN EMBARGO, si intentas ejecutar bar.py por sí solo, obtendrás:

/path2                              # "print(os.getcwd())" still works fine
Traceback (most recent call last):  # but __file__ doesn't exist if bar.py is running as main
  File "/path2/bar.py", line 3, in <module>
    print(__file__)
NameError: name '__file__' is not defined 

Espero que esto ayude. Esta advertencia me costó mucho tiempo y confusión al probar las otras soluciones presentadas.

mcstrother avatar Jun 20 '2011 19:06 mcstrother

También intentaré abordar algunas variaciones de esta pregunta:

  1. encontrar la ruta del script llamado
  2. encontrar la ruta del script que se está ejecutando actualmente
  3. encontrar el directorio del script llamado

(Algunas de estas preguntas se hicieron en SO, pero se cerraron como duplicadas y se redirigieron aquí).

Advertencias de uso__file__

Para un módulo que ha importado:

import something
something.__file__ 

devolverá la ruta absoluta del módulo. Sin embargo, dado el siguiente script foo.py:

#foo.py
print '__file__', __file__

Llamarlo con 'python foo.py' devolverá simplemente 'foo.py'. Si agrega un shebang:

#!/usr/bin/python 
#foo.py
print '__file__', __file__

y llámelo usando ./foo.py, devolverá './foo.py'. Llamándolo desde un directorio diferente (por ejemplo, coloque foo.py en la barra de directorio) y luego llamando

python bar/foo.py

o agregando un shebang y ejecutando el archivo directamente:

bar/foo.py

devolverá 'bar/foo.py' (la ruta relativa ).

Encontrar el directorio

Ahora, ir desde allí para obtener el directorio os.path.dirname(__file__)también puede ser complicado. Al menos en mi sistema, devuelve una cadena vacía si la llama desde el mismo directorio que el archivo. ex.

# foo.py
import os
print '__file__ is:', __file__
print 'os.path.dirname(__file__) is:', os.path.dirname(__file__)

generará:

__file__ is: foo.py
os.path.dirname(__file__) is: 

En otras palabras, devuelve una cadena vacía, por lo que no parece confiable si desea usarlo para el archivo actual (a diferencia del archivo de un módulo importado). Para solucionar esto, puedes envolverlo en una llamada a abspath:

# foo.py
import os
print 'os.path.abspath(__file__) is:', os.path.abspath(__file__)
print 'os.path.dirname(os.path.abspath(__file__)) is:', os.path.dirname(os.path.abspath(__file__))

que genera algo como:

os.path.abspath(__file__) is: /home/user/bar/foo.py
os.path.dirname(os.path.abspath(__file__)) is: /home/user/bar

Tenga en cuenta que abspath() NO resuelve enlaces simbólicos. Si desea hacer esto, utilice realpath() en su lugar. Por ejemplo, crear un enlace simbólico file_import_testing_link que apunte a file_import_testing.py, con el siguiente contenido:

import os
print 'abspath(__file__)',os.path.abspath(__file__)
print 'realpath(__file__)',os.path.realpath(__file__)

La ejecución imprimirá rutas absolutas algo como:

abspath(__file__) /home/user/file_test_link
realpath(__file__) /home/user/file_test.py

file_import_testing_link -> file_import_testing.py

Usando inspeccionar

@SummerBreeze menciona el uso del módulo de inspección .

Esto parece funcionar bien y es bastante conciso para módulos importados:

import os
import inspect
print 'inspect.getfile(os) is:', inspect.getfile(os)

Devuelve obedientemente el camino absoluto. Para encontrar la ruta del script que se está ejecutando actualmente:

inspect.getfile(inspect.currentframe())

(gracias @jbochi)

inspect.getabsfile(inspect.currentframe()) 

proporciona la ruta absoluta del script que se está ejecutando actualmente (gracias @Sadman_Sakib).

jpgeek avatar May 30 '2013 02:05 jpgeek

No entiendo por qué nadie habla de esto, pero para mí la solución más simple es usar imp.find_module("modulename") (documentación aquí ):

import imp
imp.find_module("os")

Da una tupla con la ruta en segunda posición:

(<open file '/usr/lib/python2.7/os.py', mode 'U' at 0x7f44528d7540>,
'/usr/lib/python2.7/os.py',
('.py', 'U', 1))

La ventaja de este método sobre el de "inspeccionar" es que no necesita importar el módulo para que funcione y puede usar una cadena en la entrada. Útil al comprobar módulos llamados en otro script, por ejemplo.

EDITAR :

En python3, importlibel módulo debería hacer:

Doctor de importlib.util.find_spec:

Devuelve la especificación para el módulo especificado.

Primero, se verifica sys.modules para ver si el módulo ya se importó. Si es así, entonces sys.modules[nombre]. Se devuelve la especificación . Si está configurado en Ninguno, se genera ValueError. Si el módulo no está en sys.modules, entonces se busca en sys.meta_path una especificación adecuada con el valor de 'ruta' proporcionado a los buscadores. No se devuelve ninguno si no se puede encontrar ninguna especificación.

Si el nombre es para submódulo (contiene un punto), el módulo principal se importa automáticamente.

Los argumentos de nombre y paquete funcionan igual que importlib.import_module(). En otras palabras, los nombres relativos de los módulos (con puntos iniciales) funcionan.

PlasmaBinturong avatar Mar 11 '2015 00:03 PlasmaBinturong