2010-11-11 16 views
8

Quindi ho capito cosa sono exec e eval e compile do. Ma perché dovrei usarli? Non sono chiaro sullo scenario di utilizzo.Uso di exec ed eval in Python

Qualcuno può darmi qualche esempio in modo da poter apprezzare meglio il concetto. Perché ho ragione, so che è tutta teoria.

+3

Fatto: cose come 'eval' sono molto raramente una scelta valida, e solo se la stringa ad essa alimentata è nota per essere sicura. – delnan

+4

Provate a cercarli nei file del codice sorgente Python nella libreria standard Python. Questo è sempre un punto di partenza interessante se vuoi vedere bene le funzionalità di base di Python. –

+0

'exec' e' eval' possono essere molto utili in [codegolfing] (https://codegolf.stackexchange.com/). – Wrzlprmft

risposta

5

Darò un esempio in cui ho utilizzato eval e dove penso sia stata la scelta migliore.

Stavo scrivendo una semplice utility di test del software ... qualcosa per verificare se gli esercizi degli studenti fossero conformi ai requisiti di assegnazione.L'obiettivo era quello di fornire un modo per un semplice file di configurazione che servisse da specifica di test (per aggirare un problema di "gallina e uovo" dell'uso di un linguaggio di programmazione per descrivere/documentare/implementare i casi di test per assegnazioni elementari di programmazione) .

Ho basato il mio cablaggio su ConfigParser nelle librerie standard. Comunque, volevo che la capacità di rappresentare le stringhe Python arbitrarie (compresi interpolazioni di \ n, \ t, e caratteri ASCII soprattutto qualsiasi esagono interpolata codificata in valori letti da esso.

La mia soluzione era un try intorno ad un parsed_string=eval('''%s''' % cfg_read_item) seguito da a try della versione a doppia virgola tripla ("" "% s" "")

Questo è un caso in cui l'alternativa sarebbe stata scrivere (o trovare un parser in linguaggio Python pre-scritto) e capire come includerlo e adattarlo al mio programma I rischi sono minimi (non sono preoccupato che il codice inviato dallo studente possa ingannare il mio parser, scoppiare se è in prigione, cancellare tutti i miei file, inviare i numeri della mia carta di credito in Romania e così via) *

* (In parte perché li stavo testando sotto Linux da un account utente headless non affidabile).

Come altri hanno già detto, ci sono altri casi di utilizzo in cui si sta costruendo codice da un modello basato su dati di input e occorre eseguire tale codice (meta programmazione). Dovresti sempre essere in grado di svolgere tali compiti in un altro modo. Tuttavia, ogni volta che quella alternativa comporta uno sforzo di codifica che si avvicina alla scrittura di un parser/compilatore/interprete di linguaggio di programmazione generale .... allora eval potrebbe essere l'approccio migliore.

0

Stai solo chiedendo un esempio? Potresti scrivere una semplice app che legge dallo standard in e consente all'utente di inserire varie espressioni, come (4*2)/8 - 1. In altre lingue (Java, C++, ecc) questo sarebbe quasi impossibile da valutare, ma in Python è semplice, basta:

eval((4*2)/8 - 1) 

Detto questo, se non si è attenti, usando queste cose possono essere molto pericoloso in quanto (essenzialmente) consentono all'utente un enorme quantità di accesso.

+1

Non "quasi impossibile da valutare" --- Python stesso è scritto principalmente in C e Python può valutare tali espressioni. È meglio dire che la valutazione delle espressioni implicherebbe tanto lavoro quanto la scrittura di un parser di un linguaggio di programmazione e di un compilatore o interprete. –

+1

@Jim Dennis. Concordato che non è "vicino all'impossibile". È fattibile dato un paio d'ore, forse anche meno. Ma è un dolore. – nosirrahcd

0

Viene utilizzato nella meta-programmazione (quando il programma si scrive). Ad esempio, hai animali di diverse specie, che sono descritti con classi diverse: Leone, Tigre, Cavallo, Asino. E tu vuoi simulare il crossbreeding tra loro, per exampe, tra Lion e Tiger. Quando si scrive il programma, non è possibile determinare in che modo l'utente attraverserà gli animali, ma è possibile creare nuove classi di animali al volo:

new_class_name = boy.class.to_str() + girl.class.to_str() 
eval("class " + new_class_name + " extends " + boy.class.to_str() + ", " + girl.class.to_str()) 

P. S. Scusa, ho dimenticato Python alcuni. Quindi c'è un sacco di pseudo-codice.

+4

No, questo non è un uso valido di 'eval' - si dovrebbe invece usare' type'. – katrielalex

1

Si non è necessario per utilizzarli e, a mio parere, è necessario evitarli.

Sono utili solo nei casi in cui si sta generando il codice stesso, che alla fine sarà probabilmente considerato una cattiva pratica.

Se si sta considerando l'utilizzo di eval() per cose come le espressioni matematiche, sarebbe meglio disinfettare l'input prima di valutarlo. Non si sa mai quale tipo di "testo" invia l'utente che potrebbe rovinare l'applicazione stessa.

+5

Avere "meta-programmazione" uguale a "cattiva pratica" è un po 'duro, IMHO. Una meta-programmazione, sebbene a volte più complessa e più soggetta a errori, può produrre un codice migliore (più veloce o più gestibile) se usato correttamente. – Kos

+1

La meta-programmazione non è una cattiva pratica. Può essere molto bello –

+0

Ogni strumento e metodo ha il suo dominio di applicazione.Ma hai ragione, il campo di applicazione della meta-programmazione è molto stretto. –

4

La libreria standard ha un esempio istruttivo su come utilizzare exec. collections.namedtuple lo utilizza per creare una classe in modo dinamico.

template = '''class %(typename)s(tuple): 
    '%(typename)s(%(argtxt)s)' \n 
    __slots__ =() \n 
    _fields = %(field_names)r \n 
    def __new__(_cls, %(argtxt)s): 
     'Create new instance of %(typename)s(%(argtxt)s)' 
     return _tuple.__new__(_cls, (%(argtxt)s)) \n 
    ...''' 

    namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename, 
        OrderedDict=OrderedDict, _property=property, _tuple=tuple) 
    try: 
     exec template in namespace 
    except SyntaxError, e: 
     raise SyntaxError(e.message + ':\n' + template) 
+2

Parlando di programmazione pazzesca ... – Unode

+0

Probabilmente lo farei con una metaclasse –

+0

utilizzando le funzioni di ordine superiore –

3

ast utilizza compile per generare albero sintattico astratto dal codice sorgente Python. Questi sono usati da moduli come pyflakes per analizzare e validare Python.

def parse(expr, filename='<unknown>', mode='exec'): 
    """ 
    Parse an expression into an AST node. 
    Equivalent to compile(expr, filename, mode, PyCF_ONLY_AST). 
    """ 
    return compile(expr, filename, mode, PyCF_ONLY_AST) 
0

Ecco un caso d'uso valido. Nel middleware di python paste (per la programmazione web) quando viene sollevata un'eccezione, crea una riga di comando all'interno del browser. Questo funziona usando metodi come questi. Inoltre, in Blender esiste un'opzione per animare valori usando espressioni python e questo funziona usando eval.

1

Penso di avere un uso valido. Sto usando Python 3.2.1 all'interno di Blender 2.6.4 per modificare un insieme di punti con coordinate x, y (nel piano z).

L'obiettivo è aggiungere anelli concentrici di nuovi punti attorno a ciascun punto esistente, con gli anelli che si comportano come increspature (come quando si rilascia una pietra in uno stagno). Il problema è che voglio che le increspature interferiscano costruttivamente/distruttivamente tra loro, quindi prima di tutto sto passando e costruendo un'equazione di ripple centrata in ogni punto e sommando tutte le equazioni di ripple in un'unica gigantesca equazione matematica, che Quindi inserirò i punti originali per generare il valore z corretto per assegnarli a.

Il mio piano è di aggiungere ogni termine aggiuntivo nell'equazione al precedente come stringa, e quindi utilizzare eval() per calcolare il valore z per il nuovo insieme di punti.