2012-05-24 9 views
7

Estoy tratando de determinar el módulo actual real de una función (como se ve si se importó desde otro lugar), incluso si el módulo actual es el "top level scripting environment" __main__.Python: determine el módulo actual actual (no __main__)

Puede parecer una cosa rara, pero el trasfondo es que necesito serializar una función y deserializarla (incluidos los argumentos) en una máquina diferente, para lo cual necesito asegurarme de que el módulo correcto Y NO __main__ se importa antes de deserializar (de lo contrario, aparece un error que dice AttributeError: 'module' object has no attribute my_fun).

Hasta ahora, he tratado inspection:

import inspect 
print inspect.getmodule(my_fun) 

que me da

<module '__main__' from 'example.py'> 

por supuesto. También traté de encontrar algo útil usando globals(), sin suerte.

Lo que realmente quiero es <module 'example' from 'example.py'>. Supongo que una manera hacky sería analizarlo desde el nombre de archivo usando algo como

m_name = __main__.__file__.split("/")[-1].replace(".pyc","") 

y luego encontrar el módulo por su nombre sys.modules[m_name].

¿Existe alguna manera más limpia/mejor para hacer esto?

EDIT: Después de aprender sobre "FakeModule" de ipython y un poco más buscando en Google, me encontré con this post, que describe exactamente el problema que estoy enfrentando, incluyendo mi solución actual a la misma (que está importando explícitamente el módulo actual import current_module y serializando current_module.my_fun en lugar de my_fun). Estoy tratando de evitar esto, ya que puede no ser intuitivo para los usuarios de mi paquete.

+0

¿Ha mirado antes las partes internas de la biblioteca 'nose', específicamente el módulo' importador'? 'nose' hace algunas cosas muy similares a esto, por lo que podría ser un buen lugar para buscar inspiración. –

Respuesta

3

En realidad encontré este mismo problema.

Lo que utilicé fue:

return os.path.splitext(os.path.basename(__main__.__file__))[0] 

que es efectivamente el mismo que su "piratear". Honestamente, creo que es la mejor solución.

+0

Gracias Winston, es la solución con la que fui y no he tenido problemas desagradables desde entonces. – soramimo

+0

Esto no funciona si está ejecutando su script dentro de una carpeta, por ejemplo, "bar/foo.py" – jwayne

+0

@jwayne, ¿qué produce en su lugar? –

2

Una forma de hacerlo, posiblemente no sea la mejor, pero me sirve, es importar sus módulos con __import__ y usar getattr de una manera similar a la siguiente.

(Aquí estoy usando algunas ideas descritas en this post módulos dinámicamente sobre la carga.)

def dynamic_import(name): 
    mod = __import__(name) 
    components = name.split('.') 
    for comp in components[1:]: 
     mod = getattr(mod, comp) 
    return mod 

tmodule = dynamic_import('modA') 
# Print the module name 
print tmodule 
# Use the module's contents 
t = tmodule.myObject() 
t.someMethod() 

Dónde modA.py se ve así:

class myObject(): 
    def someMethod(self): 
     print "I am module A" 

para que pueda ver que estamos recibiendo el nombre del módulo que hemos importado y seguir usando los objetos y métodos dentro del módulo de forma normal. Cuando ejecuto esto me sale el siguiente:

python experiment.py 
<module 'modA' from 'modA.pyc'> 
I am module A 

Una vez más, esto puede o no ser la forma "ideal", pero funciona bien y por lo que yo puedo decir no implica ningún compensaciones indeseables en la mayoría casos. Espero que esto ayude.

3

Creo que su solución original es la mejor y más simple. Si te preocupa que parezca contraintuitivo para tus usuarios, envuélvelo en una función agradable y documenta para qué sirve.

Cuando ejecuta un módulo como __main__, python realmente no lo asocia con su nombre de módulo normal: si import example, cargará el archivo una segunda vez como si fuera un módulo separado. De hecho, esto probablemente ocurra en su caso, de lo contrario no podría encontrar su módulo por nombre en sys.modules: el módulo example y el módulo __main__ son realmente objetos de tiempo de ejecución separados, ya que descubrirá si cambia explícitamente una variable de módulo en uno de ellos.

3

Sé que esto está desactualizado pero encontré una solución más simple en Python3 que funcionó para mí. Para resumir, está el __spec__ del objeto que también almacena el nombre real del módulo en lugar de ser "__main__".

import inspect 
if obj.__class_.__module__ == "__main__": 
    print(inspect.getmodule(obj).__spec__.name) 
+0

Esto solo funciona cuando se ejecuta como módulo (con 'python -m'), de lo contrario' __spec__' es 'None'. ¡Pero eso es lo suficientemente bueno para mí! (Además, para mi caso de uso, puedo omitir 'inspeccionar' y simplemente usar' import __main__; print (__ main __.__ spec __. Name) '.) –

Cuestiones relacionadas