Pregunta

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?

¿Fue útil?

Solución

import a_module
print(a_module.__file__)

En realidad, te dará la ruta al archivo .pyc que se cargó, al menos en Mac OS X. Así que supongo que puedes hacerlo:

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

También puedes probar:

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

Para obtener el directorio del módulo.

Otros consejos

Hay un módulo inspeccionar en python.

Documentación oficial

  

El módulo de inspección proporciona varias funciones útiles para ayudar a obtener   información sobre objetos vivos como módulos, clases, métodos,   funciones, trazas, objetos de marco y objetos de código. Por ejemplo,   Puede ayudarte a examinar el contenido de una clase, recuperar la fuente   código de un método, extraer y formatear la lista de argumentos para una función,   u obtenga 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 con __file__ (se muestra nuevamente a continuación). Sin embargo, hay una advertencia importante, que es que __file__ NO existe si está ejecutando el módulo por sí solo (es decir, como __main__ ).

Por ejemplo, supongamos que tiene dos archivos (ambos 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 intenta ejecutar bar.py por sí solo, obtendrá:

/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.

Intentaré abordar algunas variaciones sobre esta pregunta también:

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

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

Advertencias sobre el uso de __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, ponga foo.py en la barra de directorios), y luego llame a cualquiera de los dos

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, 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. ej.

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

dará salida:

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

En otras palabras, devuelve una cadena vacía, por lo que esto no parece confiable si desea usarlo para el archivo actual (en oposición al archivo de un modulo importado). Para evitar esto, puede 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 quieres hacer esto, usa realpath () en su lugar. Por ejemplo, hacer 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 así como:

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

file_import_testing_link - > file_import_testing.py

Usar inspeccionar

@SummerBreeze menciona el uso del módulo inspeccionar .

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. Sin embargo, para encontrar la ruta del script que se está ejecutando actualmente, no vi una manera de usarlo.

No entiendo por qué nadie está hablando de esto, pero para mí, la solución más simple es utilizar imp.find_module (" nombre de módulo ") (documentación here ):

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 " inspeccionar " una es que no necesita importar el módulo para que funcione, y puede usar una cadena en la entrada. Útil cuando se comprueban módulos llamados en otro script, por ejemplo.

EDITAR :

En python3, el módulo importlib debería hacer:

Doc. de importlib.util.find_spec :

  

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

     

Primero, se comprueba sys.modules para ver si el módulo ya se importó. Si es así, se devuelve sys.modules [nombre]. espec. . Si eso sucede   establecido en Ninguno, entonces se genera ValueError. Si el módulo no está en   sys.modules, luego se busca en sys.meta_path una especificación adecuada con el   Valor de 'ruta' dado a los buscadores. Ninguno se devuelve si ninguna especificación podría   ser encontrado.

     

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

     

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

Esto fue trivial.

Cada módulo tiene una variable __file__ que muestra su ruta relativa desde donde se encuentra ahora.

Por lo tanto, obtener un directorio para que el módulo lo notifique es tan simple como:

os.path.dirname(__file__)
import os
path = os.path.abspath(__file__)
dir_path = os.path.dirname(path)

Utilidad de línea de comandos

Puedes ajustarlo a una utilidad de línea de comandos,

python-which <package name>

 ingrese la descripción de la imagen aquí


Crear /usr/local/bin/python-which

#!/usr/bin/env python

import importlib
import os
import sys

args = sys.argv[1:]
if len(args) > 0:
    module = importlib.import_module(args[0])
    print os.path.dirname(module.__file__)

Hazlo ejecutable

sudo chmod +x /usr/local/bin/python-which

Así que pasé una buena cantidad de tiempo tratando de hacer esto con py2exe El problema era obtener la carpeta base del script si se estaba ejecutando como un script de python o como un ejecutable py2exe. También para que funcione si se estaba ejecutando desde la carpeta actual, otra carpeta o (esta fue la más difícil) desde la ruta del sistema.

Eventualmente utilicé este enfoque, utilizando sys.frozen como indicador de ejecución en py2exe:

import os,sys
if hasattr(sys,'frozen'): # only when running in py2exe this exists
    base = sys.prefix
else: # otherwise this is a regular python script
    base = os.path.dirname(os.path.realpath(__file__))
import module
print module.__path__
  

Los paquetes admiten un atributo especial más, __path__ . Esto es   inicializado para ser una lista que contiene el nombre del directorio que contiene   el paquete & # 8217; s __init__.py antes de que se ejecute el código en ese archivo.   Esta variable puede ser modificada; hacerlo afecta futuras búsquedas de   módulos y subpaquetes contenidos en el paquete.

     

Si bien esta característica no se necesita con frecuencia, se puede usar para extender   conjunto de módulos encontrados en un paquete.

Fuente

puedes importar tu módulo luego presione su nombre y obtendrá su ruta completa

>>> import os
>>> os
<module 'os' from 'C:\\Users\\Hassan Ashraf\\AppData\\Local\\Programs\\Python\\Python36-32\\lib\\os.py'>
>>>

Si la única advertencia del uso de __file__ es cuando está actual, el directorio relativo está en blanco (es decir, cuando se ejecuta como un script desde el mismo directorio donde está el script), entonces una solución trivial es:

import os.path
mydir = os.path.dirname(__file__) or '.'
full  = os.path.abspath(mydir)
print __file__, mydir, full

Y el resultado:

$ python teste.py 
teste.py . /home/user/work/teste

El truco está en o '.' después de la llamada dirname () . Establece el directorio como . , que significa directorio actual y es un directorio válido para cualquier función relacionada con la ruta.

Por lo tanto, no es realmente necesario usar abspath () . Pero si lo usa de todos modos, el truco no es necesario: abspath () acepta rutas en blanco y lo interpreta correctamente como el directorio actual.

Me gustaría contribuir con un escenario común (en Python 3) y explorar algunos enfoques.

La función integrada open () acepta cualquier pariente o ruta absoluta como su primer argumento. La ruta relativa se trata como relativa al directorio de trabajo actual , por lo que se recomienda pasar la ruta absoluta al archivo.

Simplemente dicho, si ejecuta un archivo de script con el siguiente código, no garantiza que el archivo example.txt se creará en el mismo directorio donde el archivo de script se encuentra:

with open('example.txt', 'w'):
    pass

Para arreglar este código, necesitamos obtener la ruta al script y hacerlo absoluto. Para garantizar que la ruta sea absoluta, simplemente usamos os Función .path.realpath () . Para obtener la ruta al script hay varias funciones comunes que devuelven varios resultados de ruta:

  • os.getcwd()
  • os.path.realpath('example.txt')
  • sys.argv[0font>
  • __file__

Ambas funciones os.getcwd () y < a href = "https://docs.python.org/3/library/os.path.html#os.path.realpath" rel = "nofollow noreferrer"> os.path.realpath () ruta de retorno resultados basados ??en el directorio de trabajo actual . Generalmente no es lo que queremos. El primer elemento de la sys.argv es la lista < em> ruta del script raíz (el script que ejecuta) independientemente de si llama a la lista en el propio script raíz o en cualquiera de sus módulos. Puede ser útil en algunas situaciones. La __file__ contiene la ruta del módulo desde el que se ha llamado .


El siguiente código crea correctamente un archivo example.txt en el mismo directorio donde se encuentra el script:

filedir = os.path.dirname(os.path.realpath(__file__))
filepath = os.path.join(filedir, 'example.txt')

with open(filepath, 'w'):
    pass

Desde los módulos de un paquete de Python tuve que referirme a un archivo que residía en el mismo directorio que el paquete. Ej.

some_dir/
  maincli.py
  top_package/
    __init__.py
    level_one_a/
      __init__.py
      my_lib_a.py
      level_two/
        __init__.py
        hello_world.py
    level_one_b/
      __init__.py
      my_lib_b.py

Entonces, arriba, tuve que llamar a maincli.py desde el módulo my_lib_a.py sabiendo que top_package y maincli.py están en el mismo directorio. Así es como obtengo el camino a maincli.py:

import sys
import os
import imp


class ConfigurationException(Exception):
    pass


# inside of my_lib_a.py
def get_maincli_path():
    maincli_path = os.path.abspath(imp.find_module('maincli')[1])
    # top_package = __package__.split('.')[0]
    # mod = sys.modules.get(top_package)
    # modfile = mod.__file__
    # pkg_in_dir = os.path.dirname(os.path.dirname(os.path.abspath(modfile)))
    # maincli_path = os.path.join(pkg_in_dir, 'maincli.py')

    if not os.path.exists(maincli_path):
        err_msg = 'This script expects that "maincli.py" be installed to the '\
        'same directory: "{0}"'.format(maincli_path)
        raise ConfigurationException(err_msg)

    return maincli_path

Basado en la publicación de PlasmaBinturong, modifiqué el código.

Si desea hacer esto dinámicamente en un " programa " prueba este código:
Mi punto es que es posible que no conozca el nombre exacto del módulo para '' hardcode '' eso. Puede seleccionarse de una lista o puede no estar ejecutándose actualmente para usar __file__.

(Lo sé, no funcionará en Python 3)

global modpath
modname = 'os' #This can be any module name on the fly
#Create a file called "modname.py"
f=open("modname.py","w")
f.write("import "+modname+"\n")
f.write("modpath = "+modname+"\n")
f.close()
#Call the file with execfile()
execfile('modname.py')
print modpath
<module 'os' from 'C:\Python27\lib\os.pyc'>

Intenté deshacerme de " global " problema pero encontró casos en los que no funcionó Creo que "execfile ()" se puede emular en Python 3 Dado que esto está en un programa, se puede poner fácilmente en un método o módulo para su reutilización.

Si desea conocer la ruta absoluta de su script, puede usar Ruta objeto:

from pathlib import Path

print(Path().absolute())
print(Path().resolve('.'))
print(Path().cwd())

método cwd ()

  

Devuelve un nuevo objeto de ruta que representa el directorio actual (como lo devolvió os.getcwd ())

método resolve ()

  

Haga que la ruta sea absoluta, resolviendo cualquier enlace simbólico. Se devuelve un nuevo objeto de ruta:

Si desea recuperar la ruta raíz del paquete desde cualquiera de sus módulos, los siguientes trabajos (probados en Python 3.6):

from . import __path__ as ROOT_PATH
print(ROOT_PATH)

La ruta principal __init__.py también se puede referenciar usando __file__ en su lugar.

¡Espero que esto ayude!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top