Perché fa una differenza se le variabili vengono passate come globali o come locals alla funzione di Python eval()?Qual è la differenza tra locali e globali quando si utilizza Eval() di Python?
Come anche described in the documenation, Python copierà __builtins__
a livello globale, se non fornito esplicitamente. Ma deve esserci anche qualche altra differenza che non riesco a vedere.
Considerare la seguente funzione di esempio. Prende una stringa code
e restituisce un oggetto funzione. I build non sono consentiti (ad esempio abs()
), ma tutte le funzioni dal pacchetto math
.
def make_fn(code):
import math
ALLOWED_LOCALS = {v:getattr(math, v)
for v in filter(lambda x: not x.startswith('_'), dir(math))
}
return eval('lambda x: %s' % code, {'__builtins__': None}, ALLOWED_LOCALS)
Esso funziona come previsto non utilizzare alcun oggetto locale o globale:
fn = make_fn('x + 3')
fn(5) # outputs 8
Ma non funziona utilizzando le math
funzioni:
fn = make_fn('cos(x)')
fn(5)
Emette la seguente eccezione:
<string> in <lambda>(x)
NameError: global name 'cos' is not defined
Ma quando si passa la stessa mappatura come globali funziona:
def make_fn(code):
import math
ALLOWED = {v:getattr(math, v)
for v in filter(lambda x: not x.startswith('_'), dir(math))
}
ALLOWED['__builtins__'] = None
return eval('lambda x: %s' % code, ALLOWED, {})
stesso esempio di sopra:
fn = make_fn('cos(x)')
fn(5) # outputs 0.28366218546322625
Cosa succede qui in dettaglio?
Nella documentazione si dice "il dizionario globale è presente e manca" __builtins__ "". Immagino che questo significhi che la chiave "__builtins__" non sia presente, ma nel tuo esempio la imposti su Nessuna. Ti suggerisco di cambiare CONSENTITO ['__ builtins__'] = Nessuno del DELOWED ['__ builtins__'] e riprovare. – jorispilot
@jorispilot Il mio problema non è connesso a __builtins__. L'ho appena menzionato, perché c'è questo involucro speciale dei globali per eval. Il modo in cui ho impostato __builtins__ su None è corretto, se si desidera proibire funzioni incorporate come 'abs'. 'cos' non è una funzione costruita, fa parte del modulo' math'. – lumbric