¿Cómo recuperar la ruta de un módulo?
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?
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.
Hay inspect
un 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'
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.
También intentaré abordar algunas variaciones de esta pregunta:
- encontrar la ruta del script llamado
- encontrar la ruta del script que se está ejecutando actualmente
- 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).
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, importlib
el 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.