¿Cómo puedo acceder al módulo de ejecución actual o al nombre de la clase en Python?

9 minutos de lectura

Avatar de usuario de Andrew Hare
Andrés Liebre

Me gustaría poder recuperar dinámicamente el módulo de ejecución actual o el nombre de clase desde dentro de un módulo importado. Aquí hay algo de código:

foo.py:

def f():
    print __name__

bar.py:

from foo import f

def b(): f()

Esto obviamente no funciona como __name__ es el nombre del módulo que contiene la función. Lo que me gustaría tener acceso dentro del foo módulo es el nombre del módulo de ejecución actual que está utilizando foo. Así que en el caso anterior sería bar pero si cualquier otro módulo importado foo Me gustaría foo para tener acceso dinámicamente al nombre de ese módulo.

Editar: los inspect El módulo parece bastante prometedor, pero no es exactamente lo que estaba buscando. Lo que esperaba era algún tipo de variable global o de nivel de entorno a la que pudiera acceder y que contuviera el nombre del módulo de ejecución actual. No es que no esté dispuesto a recorrer la pila para encontrar esa información, solo pensé que Python ya podría haber expuesto esos datos.

Editar: Así es como estoy tratando de usar esto. Tengo dos aplicaciones Django diferentes que necesitan registrar errores en el archivo. Digamos que se llaman “AppOne” y “AppTwo”. También tengo un lugar en el que me gustaría registrar estos archivos: “/home/hare/app_logs“. En cada aplicación, en un momento dado, me gustaría poder importar mi módulo de registro y llamar a la función de registro que escribe la cadena de registro en el archivo. Sin embargo, lo que me gustaría hacer es crear un directorio en app_logs ese es el nombre de la aplicación actual (“AppOne” o “AppTwo”) para que los archivos de registro de cada aplicación vayan a sus respectivos directorios de registro.

Para hacer esto, pensé que la mejor manera sería que el módulo de registro tuviera acceso a algún tipo de variable global que indique el nombre de la aplicación actual, ya que es responsable de conocer la ubicación del directorio de registro principal y crear el registro de la aplicación. directorio si aún no existe.

  • ¿Por qué querrías romper la asignación de responsabilidad de esta manera?

    – S. Lott

    2 de marzo de 2009 a las 16:06

  • Estoy usando esto dentro de un módulo de registro: quiero poder saber qué módulo externo está intentando iniciar sesión sin que la persona que llama tenga que pasar una clave de algún tipo.

    – Andrew Hare

    2 de marzo de 2009 a las 16:10

  • ¿Está buscando el módulo que inició la ejecución de su programa (es decir, el módulo cuyo nombre == ‘principal‘? ¿O literalmente el módulo que llamó a foo.f(), que puede ser diferente cada vez que se llama a foo.f()?

    – Jarret Hardie

    2 de marzo de 2009 a las 16:18

  • @Andrew Hare: ¿está diciendo que (a) escribió su propio registrador, diferente del módulo de registro incorporado y (b) su propio registrador no tiene una clase o función de configuración simple? ¿Y estás tratando de evitar esto?

    – S. Lott

    2 de marzo de 2009 a las 16:46

  • @S.Lott: a) sí, b) sí, y no hay ninguna solución alternativa, solo aprendo un poco las cuerdas.

    – Andrew Hare

    2 de marzo de 2009 a las 16:57

Avatar de usuario de S. Lott
S. Lott

Del comentario, no de la pregunta.

Simplemente tengo curiosidad por ver si lo que estoy tratando de hacer es posible.

La respuesta a “es posible” siempre es “sí”. Siempre. A menos que su pregunta involucre viajes en el tiempo, antigravedad o movimiento perpetuo.

Dado que la respuesta siempre es “sí”, su pregunta está mal formulada. La verdadera pregunta es “¿cuál es una buena manera de que mi módulo de registro sepa el nombre del cliente?” o algo así.

La respuesta es “Acéptalo como un parámetro”. No pierda el tiempo inspeccionando o buscando globales misteriosos u otros trucos.

Simplemente siga el patrón de diseño de logging.getLogger() y use registradores con nombres explícitos. Un modismo común es el siguiente

logger= logging.getLogger( __name__ )

Eso maneja casi todos los nombres de registros a la perfección.

  • Creo que tienes razón en que estaré mejor ajustando mi enfoque, ¡gracias!

    – Andrew Hare

    2 de marzo de 2009 a las 19:34

  • Aunque si ejecuto el script en lugar de importarlo, __name__ contendrá __main__ en lugar de la ruta real al script (como modA.submodB.pack1). ¿Hay un valor que siempre devolver la ruta del módulo independientemente de cómo se llame?

    – estani

    13 de agosto de 2012 a las 8:25


  • @estani: si lo ejecuta como un script, su nombre será ser __main__. No existe tal cosa como un nombre “real” de módulo, o modA.submodB.pack1 cuando se ejecuta de esta manera. No confunda la jerarquía de módulos con los nombres de archivo.

    – Mestre León

    28 de noviembre de 2014 a las 11:27

  • “La respuesta a ‘es posible’ siempre es ‘sí'”. O resolver problemas de NP en tiempo polinomial. Entonces es “tal vez, pero la mayoría de la gente piensa que no”. 😉

    – jpmc26

    30 de enero de 2017 a las 18:37


  • En realidad, hay un módulo antigravedad en Python (aunque no estoy seguro para viajes en el tiempo y movimiento perpetuo)

    – Tanguy

    22 de febrero de 2018 a las 16:23


Esto debería funcionar para hacer referencia al módulo actual:

import sys
sys.modules[__name__]

  • Entonces puedes usar import sys; module_name = vars(sys.modules[__name__])['__package__'] para obtener el nombre del módulo actual, o None si no un módulo. Ej: Si el código se ejecuta con python foo/bar.py, Nombre del módulo estarán None; pero con python -m foo.bar, Nombre del módulo estarán "foo".

    – roipoussiere

    17 sep 2019 a las 14:30


Avatar de usuario de Brian
Brian

El “módulo actualmente en ejecución” claramente es foo, ya que eso es lo que contiene la función que se está ejecutando actualmente. Creo que una mejor descripción de lo que desea es el módulo de la persona que llama inmediatamente a foo (que puede ser foo si está llamando af() de una función en foo llamada por una función en bar. Qué tan lejos quieras subir depende de para qué quieras esto.

En cualquier caso, suponiendo que desea la llamada inmediata, puede obtenerla recorriendo la pila de llamadas. Esto se puede lograr llamando sys._getframecon el número de niveles adecuado para caminar.

def f():
    caller = sys._getframe(1)  # Obtain calling frame
    print "Called from module", caller.f_globals['__name__']

[Edit]: En realidad, usando el inspeccionar El módulo como se sugirió anteriormente es probablemente una forma más limpia de obtener el marco de la pila. El código equivalente es:

def f():
    caller = inspect.currentframe().f_back
    print "Called from module", caller.f_globals['__name__']

(sys._getframe está documentado como para uso interno; el módulo de inspección es una API más confiable)

Avatar de usuario de Sjshovan
Sjshovan

Para obtener una referencia al “_principal_” módulo cuando en otro:

import sys
sys.modules['__main__']

Para luego obtener la ruta del archivo del módulo, que incluye su nombre:

sys.modules['__main__'].__file__  # type: str

Si está dentro del módulo “__main__”, simplemente use: __file__

Para obtener solo el nombre del archivo de la ruta del archivo:

import os
os.path.basename(file_path)

Para separar el nombre del archivo de su extensión:

file_name.split(".")[0]

Para obtener el nombre de una instancia de clase:

instance.__class__.__name__

Para obtener el nombre de una clase:

class.__name__

__file__ es la ruta del módulo actual en el que se realiza la llamada.

  • Agregando a esta solución. Para obtener el nombre de archivo de cadena en Windows. Perdonad la falta de saltos de línea. python module_name, ext = os.path.splitext(__file__) module_name = module_name.split('\\')[-1]

    – MinneapolisCoder9

    21 oct a las 14:44


Creo que lo que quieres usar es el inspeccionar módulo, para inspeccionar la pila de tiempo de ejecución de python. Mira esto tutorial. Creo que proporciona un ejemplo casi exacto de lo que quieres hacer.

  • Agregando a esta solución. Para obtener el nombre de archivo de cadena en Windows. Perdonad la falta de saltos de línea. python module_name, ext = os.path.splitext(__file__) module_name = module_name.split('\\')[-1]

    – MinneapolisCoder9

    21 oct a las 14:44


Avatar de usuario de Bruno Bronosky
bruno bronosky

Usando __file__ solo le brinda una ruta relativa para el módulo principal y una ruta absoluta para los módulos importados. Siendo conscientes de esto, podemos obtener el archivo del módulo constantemente de cualquier manera con un poco de ayuda de nuestro os.path instrumentos.

Para el uso de nombre de archivo solamente __file__.split(os.path.sep)[-1].

Para uso de ruta completa os.path.abspath(__file__).

Manifestación:

/tmp $ cat f.py
from pprint import pprint
import os
import sys

pprint({
    'sys.modules[__name__]': sys.modules[__name__],
    '__file__': __file__,
    '__file__.split(os.path.sep)[-1]': __file__.split(os.path.sep)[-1],
    'os.path.abspath(__file__)': os.path.abspath(__file__),
})

/tmp $ cat i.py
import f

Resultados:

## on *Nix ##

/tmp $ python3 f.py
{'sys.modules[__name__]': <module '__main__' from 'f.py'>,
 '__file__': 'f.py',
 '__file__.split(os.path.sep)[-1]': 'f.py',
 'os.path.abspath(__file__)': '/tmp/f.py'}

/tmp $ python3 i.py
{'sys.modules[__name__]': <module 'f' from '/tmp/f.pyc'>,
 '__file__': '/tmp/f.pyc',
 '__file__.split(os.path.sep)[-1]': 'f.pyc',
 'os.path.abspath(__file__)': '/tmp/f.pyc'}

## on Windows ##

PS C:\tmp> python3.exe f.py
{'sys.modules[__name__]': <module '__main__' from 'f.py'>,
 '__file__': 'f.py',
 '__file__.split(os.path.sep)[-1]': 'f.py',
 'os.path.abspath(__file__)': 'C:\\tools\\cygwin\\tmp\\f.py'}

PS C:\tmp> python3.exe i.py
{'sys.modules[__name__]': <module 'f' from 'C:\\tools\\cygwin\\tmp\\f.py'>,
 '__file__': 'C:\\tools\\cygwin\\tmp\\f.py',
 '__file__.split(os.path.sep)[-1]': 'f.py',
 'os.path.abspath(__file__)': 'C:\\tools\\cygwin\\tmp\\f.py'}

Si desea eliminar el ‘.py’ del final, puede hacerlo fácilmente. (Pero no olvide que puede ejecutar un ‘.pyc’ en su lugar).

  • cualquier razón para __file__.split(os.path.sep)[-1] en vez de os.path.basename(__file__) ?

    – cowbert

    10/07/2017 a las 20:20


¿Ha sido útil esta solución?