2010-06-10 10 views
27

Estoy trabajando en pypreprocessor que es un preprocesador que toma directivas c-style y pude hacer que funcione como un preprocesador tradicional (es autoconsciente y ejecuta código posprocesado sobre la marcha) excepto que rompe las importaciones de la biblioteca.¿Cómo anulo una importación de Python?

El problema es que el preprocesador se ejecuta en el archivo, lo procesa, genera en un archivo temporal y exec() el archivo temporal. Las bibliotecas que se importan deben manejarse un poco diferente, porque no se ejecutan, sino que se cargan y se vuelven accesibles para el módulo llamante.

Lo que necesito hacer es: Interrumpir la importación (ya que el preprocesador se está ejecutando en el medio de la importación), cargar el código posprocesado como tempModule y reemplazar la importación original con tempModule para engañar el script de llamada con la importación para creer que el tempModule es el módulo original.

He buscado en todas partes y hasta ahora y no tengo solución.

pregunta Este desbordamiento de pila es el más cercano que he visto en lo que va a proporcionar una respuesta: Override namespace in Python

Esto es lo que tengo.

# Remove the bytecode file created by the first import 
os.remove(moduleName + '.pyc') 

# Remove the first import 
del sys.modules[moduleName] 

# Import the postprocessed module 
tmpModule = __import__(tmpModuleName) 

# Set first module's reference to point to the preprocessed module 
sys.modules[moduleName] = tmpModule 

ModuleName es el nombre del módulo original, y tmpModuleName es el nombre del archivo de código posprocesamiento.

La parte extraña es que esta solución todavía se ejecuta completamente normal como si el primer módulo completo se cargara normalmente; a menos que elimines la última línea, obtienes un error de módulo no encontrado.

Esperemos que alguien en Stack   Overflow sepa mucho más sobre las importaciones que yo, porque esta me tiene perplejo.

Nota: Solo otorgaré una solución o, si esto no es posible en Python; la mejor y más detallada explicación de por qué esto no es imposible.

Actualización: Para cualquiera que esté interesado, aquí está el código de trabajo.

if imp.lock_held() is True: 
    del sys.modules[moduleName] 
    sys.modules[tmpModuleName] = __import__(tmpModuleName) 
    sys.modules[moduleName] = __import__(tmpModuleName) 

La parte 'imp.lock_held' detecta si el módulo está siendo cargado como una biblioteca. Las siguientes líneas hacen el resto.

+0

Usted está escribiendo un preprocesador, debe analizar los archivos antes de compilarlos. Es decir. deberías poder cambiar el 'módulo de importación' en' importación post_processed_module' antes de que el tiempo de ejecución de python cargue tu archivo, analizando el código fuente, modificándolo y colocándolo en un archivo. Después de preprocesar todo el árbol de origen _then_, puede ejecutar() el archivo raíz procesado posteriormente. – Iacopo

+0

@lacopo Desafortunadamente, el preprocesador debe importarse en el archivo que está preprocesando. Es una especie de importación, las directivas de preprocesador y preprocesador funcionarán en este archivo. ES DECIR. es autoconsumo –

Respuesta

28

¿Responde a esta pregunta? La segunda importación hace el truco.

Mod_1.py

def test_function(): 
    print "Test Function -- Mod 1" 

Mod_2.py

def test_function(): 
    print "Test Function -- Mod 2" 

prueba.py

#!/usr/bin/python 

import sys 

import Mod_1 

Mod_1.test_function() 

del sys.modules['Mod_1'] 

sys.modules['Mod_1'] = __import__('Mod_2') 

import Mod_1 

Mod_1.test_function() 
+1

Muchas gracias, esto es casi idéntico a mi implementación, pero me ayudó a hacerlo bien con un ejemplo de trabajo realmente útil. Nota: el segundo 'importar Mod_1' es redundante porque la línea anterior ya se ocupa de eso. –

+1

@EvanPlaice lo importante es que PUEDE hacer el segundo 'import Mod_1'. Hacerlo no recarga ni actualiza el módulo real, sino que ha sido reemplazado permanentemente por 'Mod_2'. – jwg

+0

@Ron, supongo que esto solo es aplicable a la versión de Python 2.x. – Abhijeet

-3

Enfoque muy extraño: emular el lenguaje de bajo nivel con uno de alto nivel. Si la primera manera simple no funciona, ¿puede ser que sea un objetivo equivocado?

BTW, el preprocesador C simplemente opera con archivos de texto y un conjunto de variables de preprocesador, no módulos de carga/descarga de alto nivel.

+2

Ummm. Un preprocesador no es un lenguaje de alto o bajo nivel. No es más que un paso adicional en la etapa lexer-analizador. Elegí c como el formato para emular porque la mayoría de la gente ya está familiarizada con él. Y la única diferencia de mi preprocesador frente al preprocesador c es, c lo hace durante el tiempo de compilación; Python es complicado porque se compila sobre la marcha. Si no se puede hacer, me gustaría tener razones específicas sobre por qué, o al menos, un intento honesto. –

8

Para definir un comportamiento de importación diferente o para subvertir totalmente el proceso de importación tendrá que escribir ganchos de importación. Ver PEP 302.

Por ejemplo,

import sys 

class MyImporter(object): 

    def find_module(self, module_name, package_path): 
     # Return a loader 
     return self 

    def load_module(self, module_name): 
     # Return a module 
     return self 

sys.meta_path.append(MyImporter()) 

import now_you_can_import_any_name 
print now_you_can_import_any_name 

Genera:

<__main__.MyImporter object at 0x009F85F0> 

Así que básicamente devuelve un nuevo módulo (que puede ser cualquier objeto), en este caso en sí. Puede usarlo para modificar el comportamiento de importación devolviendo processe_xxx en la importación de xxx.

IMO: Python no necesita un preprocesador. Lo que usted está logrando se puede lograr en sí mismo Python debido a su naturaleza muy dinámica, por ejemplo, tomando el caso del ejemplo de depuración, lo que es malo en tener en la parte superior del archivo de

debug = 1 

y más tarde

if debug: 
    print "wow" 

?

+0

@Anurag casi ... que imita la funcionalidad __import__ predeterminada actual. Lo que necesitaba era algo que pudiera deshacerse de la importación anterior y cargar una nueva bajo el nombre del anterior. –

+1

@Anurag Para responder "¿por qué python necesita un preprocesador?". Digamos que tienes el código python 2 y python 3 en el mismo archivo. Por lo tanto, rocía declaraciones 'if py2x' en todo el código.Luego, sale python 4 y decide dejar de recibir soporte para 2, ahora debe encontrar todas las declaraciones if para py2x en el código. En mi preprocesador, es tan fácil como decirle que elimine todos los bloques de código en '#ifdef py2x'. No está orientado a la funcionalidad, es para mantenimiento. Estoy tratando de crear una mejor alternativa para admitir el código 2x y 3x para dar a los escritores de la biblioteca más incentivos para admitir 3x. –

+0

@Evan Plaice, pero ¿por qué no se puede importar el gancho para cambiar la carga del módulo anterior y en su lugar cargar nuevos módulos? –

0

En Python 2 existe el módulo imputil que parece proporcionar la funcionalidad que está buscando, pero se ha eliminado en Python 3. No está muy bien documentado pero contiene una sección de ejemplo que muestra cómo puede reemplazar la importación estándar funciones.

Para Python 3 existe el módulo importlib (introducido en Python 3.1) que contiene funciones y clases para modificar la funcionalidad de importación en todo tipo de formas. Debería ser adecuado conectar su preprocesador al sistema de importación.

+0

Ya he bajado por ese camino. importlib se introdujo en 3.1 pero el tipo que lo creó también tiene un proyecto en PYPI que lo back-ports a Python 2.3. Ver http://pypi.python.org/pypi/importlib/1.0.2. –

Cuestiones relacionadas