Die Funktion »literal_eval« in Python
Oft stellt die Verwendung von »eval« ein Sicherheitsrisiko dar. »literal_eval« ist sicherer, da es nur Literale auswertet. Die Auswertung eines Literals ist weniger gefährlich als die Auswertung anderer Ausdrücke, die vom Programm als Zeichenfolge eingelesen werden.
- Auswertung (gekürzt und teilweise übersetzt)
from ast import literal_eval
literal_eval( 'a' )
Wertfehler: fehlerhafte Zeichenfolge
- Auswertung
from ast import literal_eval
literal_eval( "'a'" )
'a'
- Auswertung
from ast import literal_eval
literal_eval( "'a'" )
'a'
Der Name »literal_eval« ist besser verständlich, wenn man Fachbegriffe wie „Literal“ kennt und motiviert daher auch noch einmal das Erlernen solcher Fachbegriffe.
- Auswertung
from ast import literal_eval
literal_eval( '1' )
1
Vorzeichen und Additionen waren in Python 3.7.0a1 innerhalb der Argumentzeichenfolge erlaubt, aber inzwischen sind Additionen nicht mehr erlaubt.
- Auswertungen mit Python 3.7.0a1
from ast import literal_eval
literal_eval( '-1+2' )
1
literal_eval( '-1' )
-1
literal_eval( '1+2' )
3
Ein Aufruf wird von ›literal_eval‹ nicht ausgewertet.
- Auswertung
from ast import literal_eval
from random import random
eval( 'random()' )
0.23059239385729
literal_eval( 'random()' )
ValueError
Wenn eine Schreibweise für einen Wert eines bestimmten Typs (wie ›int‹) erwartet wird, so ist es hingegen meist richtig, zur Umwandlung jenen Typ zu verwenden.
- Auswertung
int( '123' )
123
»repr« und »literal_eval( 'a' )« ⃗
Zunächst erinnern wir daran, daß die Auswertung der Zeichenfolge »a«, also »literal_eval( 'a' )«, zu einer Fehlermeldung führt.
- Auswertung
print( 'a' )
a
- Auswertung
from ast import literal_eval
print( literal_eval( 'a' ))
NameError: name 'a' is not defined
- Auswertung
print( a )
NameError: name 'a' is not defined
Wenn die Zeichenfolge »a« das Ergebnis einer Auswertung sein soll, dann kann als auszuwertender Ausdruck »'a'« (mit Apostrophen) verwendet werden.
- Auswertung
from ast import literal_eval
print( literal_eval( "'a'" ))
a
- Auswertung
from ast import literal_eval
print( literal_eval( repr( 'a' )))
a
Im allgemeinen ergibt ›repr‹ eine Darstellung eines Wertes als Zeichenfolge, bei deren Interpretation mit »literal_eval« sich wieder der Argumentwert ergibt. Insofern ist ›repr‹ als das „Gegenteil“ von ›literal_eval‹, ›literal_eval‹ hebt ein vorhergehendes ›repr‹ wieder auf.
Um dies zu erreichen, schließt »repr« die Zeichenfolge in Apostrophe ein.
- Auswertung
print( 'a' )
a
- Auswertung
print( repr( 'a' ))
'a'
Wenn eine Zeichenfolge mit »str« (an Stelle von »repr«) in eine Zeichenfolge „gewandelt“ wird, wird sie hingegen nicht verändert.
- Auswertung
print( '[' + str( 'abc' ) + ']' )
[abc]
»repr« ähnelt »str«, aber fügt bei einer Zeichenfolge umgebende Anführungszeichen hinzu, damit die Interpretation mit »literal_eval« wieder einen str-Wert ergibt.
- Auswertung
print( '[' + repr( 'abc' ) + ']' )
['abc']
Die repr-Darstellung gibt eine Zeichenfolge als ein Zeichenfolgenliteral wieder, das in Quelltext verwendet werden kann, um die gegebene Zeichenfolge darzustellen.
- Protokoll
'def\nghi'
'def\nghi'
»print« verwendet hingegen »str«, um den Wert des Argumentausdrucks als Zeichenfolge darzustellen, die dann ausgegeben wird. Wenn der Argumentwert schon eine Zeichenfolge ist, wird er von »str« nicht verändert. Die Ausgabe einer Zeichenfolge mit »print« interpretiert »\n« dann so, wie es normalerweise gemeint ist, nämlich als ein Zeilenende.
- Protokoll
print( 'def\nghi' )
def
ghi
Interpretation von Zeichenfolgen
Die von uns als Beispiel mit Apostrophen definierte Zeichenfolgen könnte durch eine zusätzliche Auswertung als normales Zeichenfolgenliteral interpretiert werden, wodurch die darin vorkommende Zeichenfolge »\n« dann wieder als Zeilenende interpretiert wird.
- Bindung
x = r"'[Ljava.lang.Object; does not exist\nat com.example'"
- Ausgabeanweisung
print( x )
'[Ljava.lang.Object; does not exist\nat com.example'
- Ausgabe
from ast import literal_eval
print( literal_eval( x ))
[Ljava.lang.Object; does not exist
at com.example
Anmerkung zu ›repr‹ ⃗
In diesem Fall macht ›repr‹ das ›literal_eval‹ wieder rückgängig.
- Bindung
x = r"'[Ljava.lang.Object; does not exist\nat com.example'"
- Ausgabe
print( repr( literal_eval( x )))
'[Ljava.lang.Object; does not exist\nat com.example'