2010-06-10 10 views
27

Sto lavorando su pypreprocessor che è un preprocessore che prende le direttive in stile c e sono riuscito a farlo funzionare come un preprocessore tradizionale (è auto-consumante ed esegue il codice postelaborato al volo) eccetto che rompe le importazioni della biblioteca.Come sovrascrivere un'importazione Python?

Il problema è: il preprocessore esegue il file, lo elabora, restituisce un file temporaneo ed exec() il file temporaneo. Le librerie importate devono essere gestite in modo un po 'diverso, perché non vengono eseguite, ma vengono caricate e rese accessibili al modulo chiamante.

Quello che devo essere in grado di fare è: Interrompere l'importazione (dal momento che il preprocessore viene eseguito nel mezzo dell'importazione), caricare il codice postelaborato come tempModule e sostituire l'importazione originale con tempModule per ingannare lo script chiamante con l'importazione a credere che tempModule sia il modulo originale.

Ho cercato dappertutto e finora e non ho soluzione.

Questo Stack Overflow domanda è la più vicina che ho visto finora a fornire una risposta: Override namespace in Python

Ecco quello che ho.

# 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 è il nome del modulo originale e tmpModuleName è il nome del file di codice postelaborato.

La parte strana è che questa soluzione è ancora completamente normale come se il primo modulo fosse stato completato correttamente; a meno che non si rimuova l'ultima riga, si ottiene un errore non trovato nel modulo.

Speriamo che qualcuno su Stack   Overflow conosca molto di più sulle importazioni di me, perché questo mi ha bloccato.

Nota: assegnerò solo una soluzione o, se ciò non è possibile in Python; la spiegazione migliore e più dettagliata del perché questo non è impossibile.

Aggiornamento: per chiunque sia interessato, ecco il codice di lavoro.

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' rileva se il modulo viene caricato come libreria. Le seguenti linee fanno il resto.

+0

Si sta scrivendo un pre-processore, è necessario analizzare i file prima di compilarli. Cioè dovresti essere in grado di cambiare il 'modulo di importazione' in' import post_processed_module' prima che il runtime di python carichi il tuo file, analizzando il sorgente, modificandolo e inserendolo in un file. Dopo aver pre-elaborato tutto l'albero dei sorgenti, si può eseguire exec() il file root post-processato. – Iacopo

+0

@lacopo Sfortunatamente, il preprocessore deve essere importato nel file in fase di pre-elaborazione. È una specie di, importare il preprocessore e le direttive del preprocessore funzioneranno in questo file. IE. è auto-consumante. –

risposta

28

Questo risponde alla tua domanda? La seconda importazione fa il trucco.

Mod_1.py

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

Mod_2.py

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

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

Grazie mille, questo è quasi identico alla mia implementazione ma mi ha aiutato a farlo bene con un esempio di lavoro utile. Nota: il secondo 'import Mod_1' è ridondante perché la linea prima di esso si occupa già di questo. –

+1

@EvanPlaice l'importante è che tu possa fare il secondo 'import Mod_1'. Farlo non ricarica o aggiorna il modulo reale - è stato sostituito in modo permanente da 'Mod_2'. – jwg

+0

@Ron, suppongo che sia applicabile solo alla versione di Python 2.x. – Abhijeet

-3

Approccio molto strano - per emulare il linguaggio di basso livello con quello di alto livello. Se il primo modo semplice non funziona, potrebbe essere un obiettivo sbagliato?

BTW, il preprocessore C funziona semplicemente con file di testo e un set di variabili del preprocessore, non moduli caricati/scaricati di alto livello.

+2

Ummm. Un preprocessore non è un linguaggio di livello alto o basso. Non è altro che un passo in più nella fase del parser lessico. Ho scelto c come formato da emulare perché molti lo conoscono già. E l'unica differenza tra il mio preprocessore e il preprocessore c è c in fase di compilazione; Python è complicato perché si compila al volo. Se non può essere fatto mi piacerebbe ragioni specifiche per cui, o almeno, un tentativo onesto. –

8

Per definire un comportamento di importazione diverso o per sovvertire completamente il processo di importazione, è necessario scrivere ganci di importazione. Vedi PEP 302.

Ad esempio,

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 

Produce:

<__main__.MyImporter object at 0x009F85F0> 

Quindi sostanzialmente restituisce un nuovo modulo (che può essere qualsiasi oggetto), in questo caso per sé. È possibile utilizzarlo per modificare il comportamento di importazione restituendo processe_xxx all'importazione di xxx.

IMO: Python non ha bisogno di un preprocessore. Qualunque cosa si sta realizzando può essere realizzato in Python per sé a causa di essa la natura molto dinamica, per esempio, prendendo il caso dell'esempio di debug, ciò che è sbagliato con avere in cima alla lima

debug = 1 

e successivamente

if debug: 
    print "wow" 

?

+0

@Anurag quasi ... che riproduce la funzionalità predefinita __import__ di default. Quello di cui avevo bisogno, era qualcosa che potesse sbarazzarmi della vecchia importazione e caricarne una nuova con il nome del vecchio. –

+1

@Anurag Per rispondere "perché python ha bisogno di un preprocessore?". Diciamo che hai il codice python 2 e python 3 nello stesso file. Quindi, cospargere 'se py2x' dichiarazioni in tutto il codice.Quindi esce python 4 e decidi di eliminare il supporto per 2, ora devi trovare tutte le istruzioni if ​​per py2x nel codice. Nel mio preprocessore, è facile come dire di rimuovere tutti i blocchi di codice sotto "#ifdef py2x". Non è orientato verso la funzionalità è per la manutenibilità. Sto cercando di creare un'alternativa migliore per supportare il codice 2x e 3x per dare agli scrittori di biblioteca più incentivi per supportare 3x. –

+0

@Evan Plaice, ma perché non è possibile importare il hook per modificare il caricamento del vecchio modulo e caricare nuovi moduli? –

0

In Python 2 c'è il modulo imputil che sembra fornire la funzionalità che si sta cercando, ma è stato rimosso in python 3. Non è molto ben documentato ma contiene una sezione di esempio che mostra come è possibile sostituire l'importazione standard funzioni.

Per Python 3 è disponibile il modulo importlib (introdotto in Python 3.1) che contiene funzioni e classi per modificare la funzionalità di importazione in tutti i modi. Dovrebbe essere adatto per collegare il preprocessore al sistema di importazione.

+0

Ho già intrapreso questa strada. importlib è stato introdotto in 3.1 ma il tizio che lo ha creato ha anche un progetto su PYPI che lo esegue in back-port su Python 2.3. Vedi http://pypi.python.org/pypi/importlib/1.0.2. –

Problemi correlati