codice Python Hot Swapping (funzioni di tipo anatra?)
-
26-09-2019 - |
Domanda
Ho riflettuto su questo troppo a lungo e non hanno ottenuto alcuna idea, forse qualcuno di voi può aiutare.
Ho una cartella di script Python, i quali hanno lo stesso corpo circostante (letteralmente, ho generato da uno script di shell), ma hanno un pezzo che è diverso da tutti loro. In altre parole:
Top piece of code (always the same)
Middle piece of code (changes from file to file)
Bottom piece of code (always the same)
E mi sono reso conto oggi che questa è una cattiva idea, per esempio, se voglio cambiare qualcosa dall'alto o sezioni inferiori, ho bisogno di scrivere uno script di shell per farlo. (Non che questo è difficile, sembra proprio come è molto cattivo codice di saggio).
Quindi quello che voglio fare, è avere uno script python esterna che è come questo:
Top piece of code
Dynamic function that calls the middle piece of code (based on a parameter)
Bottom piece of code
E poi tutti gli altri file nella cartella python può essere semplicemente il pezzo centrale di codice. Tuttavia, modulo normale non avrebbe funzionato qui (a meno che non mi sbaglio), perché vorrei ottenere il codice ho bisogno di eseguire dal farvi riflettere, il che sarebbe una stringa, e quindi non saprei quale funzione da eseguire fino al runtime .
Così ho pensato su più di due soluzioni:
- Potrei scrivere un mucchio di istruzioni if, uno per eseguire ogni script sulla base di un certo parametro. Ho rifiutato questo, in quanto è ancora peggio del progetto precedente.
-
ho potuto utilizzare:
os.command (sys.argv [0] scriptName.py)
che eseguire lo script, ma chiamando pitone alla chiamata python non sembra molto elegante per me.
Quindi, qualcuno ha altre idee? Grazie.
Soluzione
Se si conosce il nome della funzione come una stringa e il nome del modulo come una stringa, allora si può fare
mod = __import__(module_name)
fn = getattr(mod, fn_name)
fn()
Altri suggerimenti
Un'altra possibile soluzione è quella di avere ognuno dei tuoi file ripetitivi importare la funzionalità dal file principale
from topAndBottom import top, bottom
top()
# do middle stuff
bottom()
In aggiunta alle varie risposte già postato, si consideri la Template Method modello di progettazione: fare una classe astratta come
class Base(object):
def top(self): ...
def bottom(self): ...
def middle(self): raise NotImplementedError
def doit(self):
self.top()
self.middle()
self.bottom()
Ogni modulo pluggable poi fa una classe che eredita da questo Base
e deve avere la priorità middle
con il relativo codice.
Forse non garantito per questo caso semplice (non ancora bisogno di importare il modulo giusto per istanziare la sua classe e chiamata doit
su di esso), ma comunque vale la pena tenere in mente (insieme alle sue numerose varianti divinatorio, che ho ampiamente spiegato in numerosi colloqui tecnologia ora disponibile su youtube) per i casi in cui il numero o la complessità di "pezzi pluggable" continua a crescere - Template Method (nonostante il suo nome orrido ;-) è un modello solido, ben collaudato e altamente scalabile [[ a volte un po 'troppo rigida, ma questo è esattamente quello che mi rivolgo a quei molti colloqui di tecnologia - e questo problema non si applica a questo specifico caso d'uso]]
Tuttavia, il modulo normale sarebbe non lavorare qui (a meno che non mi sbaglio), perché vorrei ottenere il codice ho bisogno di eseguire dal farvi riflettere, il che sarebbe una stringa, e quindi non saprei quale funzione di aperta fino al tempo di esecuzione.
Si lavorerà bene - uso __import__
incorporata o, se si hanno layout molto complessi, imp modulo di importare lo script. E allora si può ottenere la funzione module.__dict__[funcname]
per esempio.
L'importazione di un modulo (come spiegato in altre risposte) è sicuramente il modo più pulito per fare questo, ma se per qualche motivo che non funziona, a patto che non si sta facendo nulla di troppo strano è possibile utilizzare exec
. Si corre in sostanza il contenuto di un altro file come se fosse incluso nel file corrente nel punto in cui è chiamato exec
. E 'la cosa più vicina Python ha una dichiarazione source
del genere inclusi in molte conchiglie. Come minimo, qualcosa di simile a questo dovrebbe funzionare:
exec(open(filename).read(None))
Che ne dici di questo?
function do_thing_one():
pass
function do_thing_two():
pass
dispatch = { "one" : do_thing_one,
"two" : do_thing_two,
}
# do something to get your string from the command line (optparse, argv, whatever)
# and put it in variable "mystring"
# do top thing
f = dispatch[mystring]
f()
# do bottom thing