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.
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 (comomodA.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, omodA.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, oNone
si no un módulo. Ej: Si el código se ejecuta conpython foo/bar.py
, Nombre del módulo estaránNone
; pero conpython -m foo.bar
, Nombre del módulo estarán"foo"
.– roipoussiere
17 sep 2019 a las 14:30
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._getframe
con 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)
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
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 deos.path.basename(__file__)
?– cowbert
10/07/2017 a las 20:20
¿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