Ho cercato a valutazione dinamica di codice Python, e venire attraverso l' eval()
e compile()
funzioni, e la exec
dichiarazione.
Qualcuno può spiegare la differenza tra eval
e exec
e come si compile()
adattano le diverse modalità ?
Ho cercato a valutazione dinamica di codice Python, e venire attraverso l' eval()
e compile()
funzioni, e la exec
dichiarazione.
Qualcuno può spiegare la differenza tra eval
e exec
e come si compile()
adattano le diverse modalità ?
Risposte:
Fondamentalmente, eval
viene utilizzato per eval UATE una singola espressione Python generato dinamicamente, e exec
viene utilizzato per exec ute generato dinamicamente codice Python solo per i suoi effetti collaterali.
eval
e exec
hanno queste due differenze:
eval
accetta solo una singola espressione , exec
può accettare un blocco di codice con istruzioni Python: loop try: except:
, class
e funzioni / metodi def
e così via.
Un'espressione in Python è qualunque cosa tu possa avere come valore in un'assegnazione variabile:
a_variable = (anything you can put within these parentheses is an expression)
eval
restituisce il valore dell'espressione data, mentre exec
ignora il valore restituito dal suo codice e restituisce sempre None
(in Python 2 è un'istruzione e non può essere utilizzata come espressione, quindi in realtà non restituisce nulla).
Nelle versioni 1.0 - 2.7, exec
era un'affermazione, perché CPython doveva produrre un diverso tipo di oggetto codice per le funzioni usate exec
per i suoi effetti collaterali all'interno della funzione.
In Python 3, exec
è una funzione; il suo utilizzo non ha alcun effetto sul bytecode compilato della funzione in cui viene utilizzato.
Quindi sostanzialmente:
>>> a = 5
>>> eval('37 + a') # it is an expression
42
>>> exec('37 + a') # it is an expression statement; value is ignored (None is returned)
>>> exec('a = 47') # modify a global variable as a side effect
>>> a
47
>>> eval('a = 47') # you cannot evaluate a statement
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
a = 47
^
SyntaxError: invalid syntax
Il compile
in 'exec'
modalità compila un qualsiasi numero di dichiarazioni in un bytecode che implicitamente restituisce sempre None
, mentre in 'eval'
modalità si compila una singola espressione in bytecode che restituisce il valore di tale espressione.
>>> eval(compile('42', '<string>', 'exec')) # code returns None
>>> eval(compile('42', '<string>', 'eval')) # code returns 42
42
>>> exec(compile('42', '<string>', 'eval')) # code returns 42,
>>> # but ignored by exec
Nella 'eval'
modalità (e quindi con la eval
funzione se viene passata una stringa), compile
genera un'eccezione se il codice sorgente contiene istruzioni o qualsiasi altra cosa oltre una singola espressione:
>>> compile('for i in range(3): print(i)', '<string>', 'eval')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
for i in range(3): print(i)
^
SyntaxError: invalid syntax
In realtà l'istruzione "eval accetta solo una singola espressione" si applica solo quando viene passata una stringa (che contiene il codice sorgente Python ) eval
. Quindi viene compilato internamente in bytecode usando compile(source, '<string>', 'eval')
Questo è da dove proviene davvero la differenza.
Se un code
oggetto (che contiene il bytecode Python ) viene passato exec
o eval
, si comportano in modo identico , ad eccezione del fatto che exec
ignora il valore restituito, sempre restituendo None
sempre. Quindi è possibile usare eval
per eseguire qualcosa che ha delle istruzioni, se lo hai appena compile
inserito in bytecode invece di passarlo come una stringa:
>>> eval(compile('if 1: print("Hello")', '<string>', 'exec'))
Hello
>>>
funziona senza problemi, anche se il codice compilato contiene istruzioni. Restituisce ancora None
, perché quello è il valore restituito dall'oggetto codice restituito compile
.
Nella 'eval'
modalità (e quindi con la eval
funzione se viene passata una stringa), compile
genera un'eccezione se il codice sorgente contiene istruzioni o qualsiasi altra cosa oltre una singola espressione:
>>> compile('for i in range(3): print(i)', '<string>'. 'eval')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
for i in range(3): print(i)
^
SyntaxError: invalid syntax
exec
e eval
La exec
funzione (che era un'istruzione in Python 2 ) viene utilizzata per eseguire un'istruzione o un programma creati dinamicamente:
>>> program = '''
for i in range(3):
print("Python is cool")
'''
>>> exec(program)
Python is cool
Python is cool
Python is cool
>>>
La eval
funzione fa lo stesso per una singola espressione , e restituisce il valore dell'espressione:
>>> a = 2
>>> my_calculation = '42 * a'
>>> result = eval(my_calculation)
>>> result
84
exec
e eval
sia accettare il programma / espressione da eseguire sia come str
, unicode
o bytes
codice sorgente oggetto contenente, o come un code
oggetto che contiene bytecode Python.
Se un str
/ unicode
/ bytes
contenente il codice sorgente è stato passato a exec
, si comporta in modo equivalente a:
exec(compile(source, '<string>', 'exec'))
e si eval
comporta allo stesso modo equivalente a:
eval(compile(source, '<string>', 'eval'))
Dato che tutte le espressioni possono essere usate come istruzioni in Python (questi sono chiamati Expr
nodi nella grammatica astratta di Python ; non è vero il contrario), puoi sempre usare exec
se non hai bisogno del valore restituito. Vale a dire, è possibile utilizzare uno eval('my_func(42)')
o exec('my_func(42)')
, la differenza è che eval
restituisce il valore restituito da my_func
e lo exec
scarta:
>>> def my_func(arg):
... print("Called with %d" % arg)
... return arg * 2
...
>>> exec('my_func(42)')
Called with 42
>>> eval('my_func(42)')
Called with 42
84
>>>
Del 2, solo exec
accetta il codice sorgente che contiene affermazioni, come def
, for
, while
, import
, o class
, l'istruzione di assegnazione (alias a = 42
), o interi programmi:
>>> exec('for i in range(3): print(i)')
0
1
2
>>> eval('for i in range(3): print(i)')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
for i in range(3): print(i)
^
SyntaxError: invalid syntax
Entrambi exec
e eval
accettano 2 ulteriori argomenti posizionali - globals
e locals
- che sono gli ambiti delle variabili globali e locali che il codice vede. Questi sono predefiniti globals()
e locals()
nell'ambito che ha chiamato exec
o eval
, ma è possibile utilizzare qualsiasi dizionario per globals
e qualsiasi mapping
per locals
(incluso dict
ovviamente). Questi possono essere usati non solo per limitare / modificare le variabili che il codice vede, ma spesso sono anche usati per catturare le variabili exec
create dal codice uted:
>>> g = dict()
>>> l = dict()
>>> exec('global a; a, b = 123, 42', g, l)
>>> g['a']
123
>>> l
{'b': 42}
(Se si visualizza il valore dell'intero g
, sarebbe molto più lungo, perché exec
e eval
aggiungere automaticamente il modulo integrato __builtins__
ai globuli se manca).
In Python 2, la sintassi ufficiale per l' exec
istruzione è in realtà exec code in globals, locals
, come in
>>> exec 'global a; a, b = 123, 42' in g, l
Tuttavia, anche la sintassi alternativa exec(code, globals, locals)
è sempre stata accettata (vedi sotto).
compile
Il compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)
built-in può essere utilizzato per accelerare ripetute invocazioni dello stesso codice con exec
o eval
compilando in code
anticipo la fonte in un oggetto. Il mode
parametro controlla il tipo di frammento di codice compile
accettato dalla funzione e il tipo di bytecode che produce. Le scelte sono 'eval'
, 'exec'
e 'single'
:
'eval'
mode si aspetta una singola espressione e produrrà bytecode che quando eseguito restituirà il valore di quell'espressione :
>>> dis.dis(compile('a + b', '<string>', 'eval'))
1 0 LOAD_NAME 0 (a)
3 LOAD_NAME 1 (b)
6 BINARY_ADD
7 RETURN_VALUE
'exec'
accetta qualsiasi tipo di costrutto Python da singole espressioni a interi moduli di codice e li esegue come se fossero istruzioni di livello superiore del modulo. L'oggetto codice restituisce None
:
>>> dis.dis(compile('a + b', '<string>', 'exec'))
1 0 LOAD_NAME 0 (a)
3 LOAD_NAME 1 (b)
6 BINARY_ADD
7 POP_TOP <- discard result
8 LOAD_CONST 0 (None) <- load None on stack
11 RETURN_VALUE <- return top of stack
'single'
è una forma limitata 'exec'
che accetta un codice sorgente contenente una singola istruzione (o più istruzioni separate da ;
) se l'ultima istruzione è un'istruzione di espressione, il bytecode risultante stamparepr
anche il valore di quella espressione sull'output standard (!) .
Un if
- elif
- else
catena, un ciclo con else
, e try
con la sua except
, else
e finally
blocchi è considerato una singola istruzione.
Un frammento di sorgente contenente 2 istruzioni di livello superiore è un errore per 'single'
, tranne che in Python 2 è presente un bug che a volte consente più istruzioni di livello superiore nel codice; viene compilato solo il primo; il resto viene ignorato:
In Python 2.7.8:
>>> exec(compile('a = 5\na = 6', '<string>', 'single'))
>>> a
5
E in Python 3.4.2:
>>> exec(compile('a = 5\na = 6', '<string>', 'single'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
a = 5
^
SyntaxError: multiple statements found while compiling a single statement
Questo è molto utile per creare shell Python interattive. Tuttavia, il valore dell'espressione non viene restituito , anche se si ottiene eval
il codice risultante.
Quindi la più grande distinzione exec
e in eval
realtà viene dalla compile
funzione e dalle sue modalità.
Oltre a compilare il codice sorgente in bytecode, compile
supporta la compilazione di alberi di sintassi astratti (alberi di analisi del codice Python) in code
oggetti; e il codice sorgente in alberi di sintassi astratti ( ast.parse
è scritto in Python e chiama semplicemente compile(source, filename, mode, PyCF_ONLY_AST)
); questi vengono utilizzati ad esempio per modificare il codice sorgente al volo e anche per la creazione di codice dinamico, poiché è spesso più semplice gestire il codice come un albero di nodi anziché linee di testo in casi complessi.
Mentre eval
ti permette solo di valutare una stringa che contiene una singola espressione, puoi eval
un'intera istruzione, o anche un intero modulo che è stato compile
convertito in bytecode; vale a dire, con Python 2, print
è un'istruzione e non può essere eval
guidato direttamente:
>>> eval('for i in range(3): print("Python is cool")')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
for i in range(3): print("Python is cool")
^
SyntaxError: invalid syntax
compile
con 'exec'
modalità in un code
oggetto e puoi eval
farlo ; la eval
funzione tornerà None
.
>>> code = compile('for i in range(3): print("Python is cool")',
'foo.py', 'exec')
>>> eval(code)
Python is cool
Python is cool
Python is cool
Se uno esamina eval
e exec
il codice sorgente in CPython 3, questo è molto evidente; entrambi chiamano PyEval_EvalCode
con gli stessi argomenti, l'unica differenza è che exec
ritorna esplicitamenteNone
.
exec
tra Python 2 e Python 3Una delle principali differenze in Python 2 è che exec
è un'istruzione ed eval
è una funzione integrata (entrambe sono funzioni integrate in Python 3). È risaputo che la sintassi ufficiale di exec
in Python 2 è exec code [in globals[, locals]]
.
Diversamente dalla maggior parte delle guide di porting da 2 a 3 di Python sembrano suggerire , l' istruzione in CPython 2 può anche essere usata con una sintassi che assomiglia esattamente alla chiamata della funzione in Python 3. Il motivo è che Python 0.9.9 aveva il build- in funzione! E quella funzione integrata è stata sostituita con un'istruzione da qualche parte prima della versione 1.0 di Python . exec
exec
exec(code, globals, locals)
exec
Dal momento che era desiderabile non rompere la compatibilità con Python 0.9.9, nel 1993 Guido van Rossum aggiunse un hack di compatibilità : se code
fosse una tupla di lunghezza 2 o 3 globals
e locals
non fosse passata exec
nell'affermazione in caso contrario, code
sarebbe interpretata come se il 2o e il 3o elemento della tupla fossero rispettivamente globals
e locals
. L'hack di compatibilità non è stato menzionato nemmeno nella documentazione di Python 1.4 (la prima versione disponibile online) ; e quindi non era noto a molti scrittori delle guide e degli strumenti per il porting, fino a quando non è stato nuovamente documentato nel novembre 2012 :
La prima espressione può anche essere una tupla di lunghezza 2 o 3. In questo caso, le parti opzionali devono essere omesse. Il modulo
exec(expr, globals)
è equivalente aexec expr in globals
, mentre il moduloexec(expr, globals, locals)
è equivalente aexec expr in globals, locals
. La forma tupla diexec
fornisce la compatibilità con Python 3, doveexec
è una funzione piuttosto che un'istruzione.
Sì, in CPython 2.7 viene definita come un'opzione di compatibilità diretta (perché confondere le persone sul fatto che esiste un'opzione di compatibilità con le versioni precedenti), quando in realtà era lì da due decenni per la compatibilità con le versioni precedenti .
Quindi, mentre exec
è un'istruzione in Python 1 e Python 2 e una funzione integrata in Python 3 e Python 0.9.9,
>>> exec("print(a)", globals(), {'a': 42})
42
ha avuto un comportamento identico in ogni versione di Python ampiamente diffusa di sempre; e funziona anche in Jython 2.5.2, PyPy 2.3.1 (Python 2.7.6) e IronPython 2.6.1 (complimenti per loro seguendo da vicino il comportamento non documentato di CPython).
Quello che non puoi fare in Pythons 1.0 - 2.7 con il suo hack di compatibilità, è memorizzare il valore di ritorno exec
in una variabile:
Python 2.7.11+ (default, Apr 17 2016, 14:00:29)
[GCC 5.3.1 20160413] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a = exec('print(42)')
File "<stdin>", line 1
a = exec('print(42)')
^
SyntaxError: invalid syntax
(che non sarebbe utile neanche in Python 3, come exec
sempre restituisce None
), o passa un riferimento a exec
:
>>> call_later(exec, 'print(42)', delay=1000)
File "<stdin>", line 1
call_later(exec, 'print(42)', delay=1000)
^
SyntaxError: invalid syntax
Quale modello che qualcuno avrebbe potuto effettivamente usare, sebbene improbabile;
O usalo nella comprensione di un elenco:
>>> [exec(i) for i in ['print(42)', 'print(foo)']
File "<stdin>", line 1
[exec(i) for i in ['print(42)', 'print(foo)']
^
SyntaxError: invalid syntax
che è un abuso della comprensione dell'elenco (utilizzare for
invece un ciclo!).
42
è anche un'espressione e non puoi usarla @
come decoratore.
decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE
; cioè non puoi usare espressioni arbitrarie come decoratori, SOLO un identificatore (forse punteggiato), seguito da argomenti di chiamata opzionali.
a = b = c
è un'affermazione perfettamente valida, così come il suo lato destro b = c
- che non è un'espressione.
exec
non è un'espressione: un'istruzione in Python 2.xe una funzione in Python 3.x. Compila e valuta immediatamente un'istruzione o un insieme di istruzioni contenuti in una stringa. Esempio:
exec('print(5)') # prints 5.
# exec 'print 5' if you use Python 2.x, nor the exec neither the print is a function there
exec('print(5)\nprint(6)') # prints 5{newline}6.
exec('if True: print(6)') # prints 6.
exec('5') # does nothing and returns nothing.
eval
è una funzione incorporata ( non un'istruzione), che valuta un'espressione e restituisce il valore che produce l'espressione. Esempio:
x = eval('5') # x <- 5
x = eval('%d + 6' % x) # x <- 11
x = eval('abs(%d)' % -100) # x <- 100
x = eval('x = 5') # INVALID; assignment is not an expression.
x = eval('if 1: x = 4') # INVALID; if is a statement, not an expression.
compile
è una versione di livello inferiore di exec
e eval
. Non esegue o valuta le tue dichiarazioni o espressioni, ma restituisce un oggetto codice che può farlo. Le modalità sono le seguenti:
compile(string, '', 'eval')
restituisce l'oggetto codice che sarebbe stato eseguito se lo avessi fatto eval(string)
. Si noti che non è possibile utilizzare le istruzioni in questa modalità; è valida solo un'espressione (singola).compile(string, '', 'exec')
restituisce l'oggetto codice che sarebbe stato eseguito se lo avessi fatto exec(string)
. Puoi usare qualsiasi numero di dichiarazioni qui.compile(string, '', 'single')
è come la exec
modalità, ma ignorerà tutto tranne la prima istruzione. Notare che un'istruzione if
/ else
con i suoi risultati è considerata una singola istruzione.exec()
ora è in effetti una funzione.
exec
è un'affermazione nella versione che stavi prendendo di mira, è ingannevole includere quelle parentesi e, se provi a usare in globals, locals
, anche buggy.
exec
supporta le parentesi e funziona come l'invocazione in Python 2 .
x = (y)
, potrebbe essere vero. Un'altra istruzione trasformata in funzione è print
; confronta il risultato di print(1, 2, 3)
in Python 2 e 3.
exec è per dichiarazione e non restituisce nulla. eval è per espressione e restituisce valore di espressione.
espressione significa "qualcosa" mentre istruzione significa "fai qualcosa".
[i for i in globals().values() if hasattr(i, '__call__')][0]
un'affermazione o espressione? Se fosse un'espressione, perché non posso usarlo@
come decoratore?