Python Language
Dynamische code-uitvoering met `exec` en` eval`
Zoeken…
Syntaxis
- eval (expression [, globals = None [, locals = None]])
- exec (object)
- exec (object, globals)
- exec (object, globals, locals)
parameters
Argument | Details |
---|---|
expression | De expressiecode als een tekenreeks of een code object |
object | De instructiecode als een tekenreeks of een code object |
globals | Het woordenboek dat moet worden gebruikt voor globale variabelen. Als de lokale bevolking niet is opgegeven, wordt dit ook gebruikt voor de lokale bevolking. Indien weggelaten, worden de globals() van globals() gebruikt. |
locals | Een toewijzingsobject dat wordt gebruikt voor lokale variabelen. Als dit wordt weggelaten, wordt in plaats daarvan degene gebruikt die voor globals is doorgegeven. Als beide worden weggelaten, worden de globals() en locals() van het globals gebruikt voor respectievelijk globals en locals . |
Opmerkingen
In exec
, als globals
locals
(dat wil zeggen dat ze naar hetzelfde object verwijzen), wordt de code uitgevoerd alsof deze zich op moduleniveau bevindt. Als globals
en locals
verschillende objecten zijn, wordt de code uitgevoerd alsof deze in een hoofdgedeelte van de klasse staat .
Als het globals
object wordt doorgegeven, maar geen __builtins__
sleutel opgeeft, worden de ingebouwde functies en namen van Python automatisch toegevoegd aan het globale bereik. Om de beschikbaarheid van functies zoals onderdrukken print
of isinstance
in de uitgevoerde scope, laat globals
de sleutel __builtins__
toegewezen aan waarde None
. Dit is echter geen beveiligingsfunctie.
De Python 2-specifieke syntaxis mag niet worden gebruikt; de syntaxis van Python 3 werkt in Python 2. De volgende formulieren zijn dus verouderd: <s>
-
exec object
-
exec object in globals
-
exec object in globals, locals
Uitspraken evalueren met exec
>>> code = """for i in range(5):\n print('Hello world!')"""
>>> exec(code)
Hello world!
Hello world!
Hello world!
Hello world!
Hello world!
Een uitdrukking evalueren met eval
>>> expression = '5 + 3 * a'
>>> a = 5
>>> result = eval(expression)
>>> result
20
Een uitdrukking vooraf compileren om deze meerdere keren te evalueren
compile
ingebouwde functie kan worden gebruikt om een uitdrukking vooraf te compile
naar een code-object; dit code-object kan vervolgens worden doorgegeven aan eval. Dit versnelt het herhaald uitvoeren van de geëvalueerde code. De derde te compile
parameter moet de string 'eval'
.
>>> code = compile('a * b + c', '<string>', 'eval')
>>> code
<code object <module> at 0x7f0e51a58830, file "<string>", line 1>
>>> a, b, c = 1, 2, 3
>>> eval(code)
5
Een expressie evalueren met eval met behulp van aangepaste globals
>>> variables = {'a': 6, 'b': 7}
>>> eval('a * b', globals=variables)
42
Als een plus, hiermee kan de code niet per ongeluk verwijzen naar de buiten gedefinieerde namen:
>>> eval('variables')
{'a': 6, 'b': 7}
>>> eval('variables', globals=variables)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'variables' is not defined
Het gebruik van defaultdict
maakt het bijvoorbeeld mogelijk om ongedefinieerde variabelen op nul te zetten:
>>> from collections import defaultdict
>>> variables = defaultdict(int, {'a': 42})
>>> eval('a * c', globals=variables) # note that 'c' is not explicitly defined
0
Evaluatie van een string met een Python letterlijk met ast.literal_eval
Als je een string hebt die Python-literalen bevat, zoals strings, floats enz., ast.literal_eval
je ast.literal_eval
gebruiken om de waarde ast.literal_eval
te evalueren in plaats van eval
. Dit heeft de toegevoegde functie dat alleen bepaalde syntaxis wordt toegestaan.
>>> import ast
>>> code = """(1, 2, {'foo': 'bar'})"""
>>> object = ast.literal_eval(code)
>>> object
(1, 2, {'foo': 'bar'})
>>> type(object)
<class 'tuple'>
Dit is echter niet veilig voor de uitvoering van code die wordt aangeboden door niet-vertrouwde gebruikers, en het is triviaal om een tolk met zorgvuldig vervaardigde invoer te laten crashen
>>> import ast
>>> ast.literal_eval('()' * 1000000)
[5] 21358 segmentation fault (core dumped) python3
Hier is de invoer een reeks van ()
die een miljoen keer wordt herhaald, wat een crash in CPython parser veroorzaakt. CPython-ontwikkelaars beschouwen bugs in parser niet als beveiligingsproblemen.
Code uitgevoerd door niet-vertrouwde gebruiker met behulp van exec, eval of ast.literal_eval
Het is niet mogelijk om eval
of exec
te gebruiken om code van niet-vertrouwde gebruikers veilig uit te voeren. Zelfs ast.literal_eval
is gevoelig voor crashes in de parser. Het is soms mogelijk om te waken tegen het uitvoeren van schadelijke code, maar het sluit de mogelijkheid van regelrechte crashes in de parser of de tokenizer niet uit.
Om code door een niet-vertrouwde gebruiker te evalueren, moet u zich wenden tot een module van derden, of misschien uw eigen parser en uw eigen virtuele machine in Python schrijven.