tokenize — Tokenizer für Python-Quellcode¶
Quellcode: Lib/tokenize.py
Das Modul tokenize stellt einen in Python implementierten lexikalischen Scanner für Python-Quellcode bereit. Der Scanner in diesem Modul gibt auch Kommentare als Token zurück, was ihn nützlich für die Implementierung von „Pretty-Printern“ macht, einschließlich Farbgebern für Bildschirmanzeigen.
Um die Handhabung von Token-Streams zu vereinfachen, werden alle Operator- und Trennzeichen-Token sowie Ellipsis mit dem generischen Token-Typ OP zurückgegeben. Der genaue Typ kann durch Überprüfung der Eigenschaft exact_type des benannten Tupels ermittelt werden, das von tokenize.tokenize() zurückgegeben wird.
Warnung
Beachten Sie, dass die Funktionen in diesem Modul nur darauf ausgelegt sind, syntaktisch gültigen Python-Code zu parsen (Code, der beim Parsen mit ast.parse() keine Ausnahme auslöst). Das Verhalten der Funktionen in diesem Modul ist bei ungültigem Python-Code **nicht definiert** und kann sich jederzeit ändern.
Tokenisierung von Eingaben¶
Der primäre Einstiegspunkt ist ein Generator
- tokenize.tokenize(readline)¶
Der Generator
tokenize()benötigt ein Argument, readline, das ein aufrufbares Objekt sein muss, das die gleiche Schnittstelle wie die Methodeio.IOBase.readline()von Datei-Objekten bereitstellt. Jeder Aufruf der Funktion sollte eine Eingabezeile als Bytes zurückgeben.Der Generator erzeugt 5-Tupel mit diesen Mitgliedern: der Token-Typ; der Token-String; ein 2-Tupel
(srow, scol)aus Ganzzahlen, das die Zeile und Spalte angibt, an denen das Token in der Quelle beginnt; ein 2-Tupel(erow, ecol)aus Ganzzahlen, das die Zeile und Spalte angibt, an denen das Token in der Quelle endet; und die Zeile, in der das Token gefunden wurde. Die übergebene Zeile (das letzte Tupel-Element) ist die *physikalische* Zeile. Das 5-Tupel wird als benanntes Tupel mit den Feldnamen zurückgegeben:type string start end line.Das zurückgegebene benannte Tupel hat eine zusätzliche Eigenschaft namens
exact_type, die den exakten Operatortyp fürOP-Token enthält. Für alle anderen Token-Typen istexact_typegleich dem Feldtypedes benannten Tupels.Geändert in Version 3.1: Unterstützung für benannte Tupel hinzugefügt.
Geändert in Version 3.3: Unterstützung für
exact_typehinzugefügt.tokenize()ermittelt die Quellcodierung der Datei, indem es nach einem UTF-8 BOM oder einem Codierungs-Cookie gemäß PEP 263 sucht.
- tokenize.generate_tokens(readline)¶
Tokenisiert eine Quelle und liest Unicode-Strings anstelle von Bytes.
Wie
tokenize()erwartet das Argument readline eine aufrufbare Funktion, die eine einzelne Eingabezeile zurückgibt.generate_tokens()erwartet jedoch, dass readline ein str-Objekt und nicht Bytes zurückgibt.Das Ergebnis ist ein Iterator, der benannte Tupel liefert, genau wie
tokenize(). Er liefert keinENCODING-Token.
Alle Konstanten aus dem Modul token werden ebenfalls aus tokenize exportiert.
Eine weitere Funktion wird bereitgestellt, um den Tokenisierungsprozess umzukehren. Dies ist nützlich für die Erstellung von Werkzeugen, die ein Skript tokenisieren, den Token-Stream ändern und das geänderte Skript zurückschreiben.
- tokenize.untokenize(iterable)¶
Konvertiert Tokens zurück in Python-Quellcode. Das iterable muss Sequenzen mit mindestens zwei Elementen zurückgeben: den Token-Typ und den Token-String. Zusätzliche Sequenzelemente werden ignoriert.
Das Ergebnis tokenisiert garantiert zurück, um der Eingabe zu entsprechen, sodass die Konvertierung verlustfrei ist und Round-Trips gewährleistet sind. Die Garantie gilt nur für den Token-Typ und den Token-String, da der Abstand zwischen den Tokens (Spaltenpositionen) sich ändern kann.
Es gibt Bytes zurück, kodiert mit dem
ENCODING-Token, das die erste Token-Sequenz ist, die vontokenize()ausgegeben wird. Wenn kein Codierungs-Token in der Eingabe vorhanden ist, wird stattdessen ein str zurückgegeben.
tokenize() muss die Codierung von Quelldateien erkennen, die es tokenisiert. Die Funktion, die es dafür verwendet, ist verfügbar
- tokenize.detect_encoding(readline)¶
Die Funktion
detect_encoding()wird verwendet, um die Codierung zu erkennen, die zum Dekodieren einer Python-Quelldatei verwendet werden sollte. Sie erfordert ein Argument, readline, auf die gleiche Weise wie der Generatortokenize().Sie ruft readline maximal zweimal auf und gibt die verwendete Codierung (als String) und eine Liste von Zeilen (nicht aus Bytes dekodiert) zurück, die sie gelesen hat.
Sie erkennt die Codierung anhand der Anwesenheit eines UTF-8 BOM oder eines Codierungs-Cookies, wie in PEP 263 spezifiziert. Wenn sowohl ein BOM als auch ein Cookie vorhanden sind, diese aber nicht übereinstimmen, wird eine
SyntaxErrorausgelöst. Beachten Sie, dass, wenn das BOM gefunden wird,'utf-8-sig'als Codierung zurückgegeben wird.Wenn keine Codierung angegeben ist, wird standardmäßig
'utf-8'zurückgegeben.Verwenden Sie
open(), um Python-Quelldateien zu öffnen: sie verwendetdetect_encoding(), um die Dateicodierung zu erkennen.
- tokenize.open(filename)¶
Öffnet eine Datei im schreibgeschützten Modus unter Verwendung der von
detect_encoding()erkannten Codierung.Hinzugefügt in Version 3.2.
- exception tokenize.TokenError¶
Wird ausgelöst, wenn entweder ein Docstring oder ein Ausdruck, der sich über mehrere Zeilen erstrecken kann, nirgendwo in der Datei abgeschlossen wird, zum Beispiel
"""Beginning of docstring
oder
[1, 2, 3
Befehlszeilenverwendung¶
Hinzugefügt in Version 3.3.
Das Modul tokenize kann von der Kommandozeile als Skript ausgeführt werden. Es ist so einfach wie
python -m tokenize [-e] [filename.py]
Die folgenden Optionen werden akzeptiert:
- -h, --help¶
Hilfemeldung anzeigen und beenden
- -e, --exact¶
Tokennamen unter Verwendung des exakten Typs anzeigen
Wenn filename.py angegeben ist, wird sein Inhalt an stdout tokenisiert. Andernfalls wird die Tokenisierung über stdin durchgeführt.
Beispiele¶
Beispiel für einen Skript-Rewriter, der Float-Literale in Decimal-Objekte umwandelt
from tokenize import tokenize, untokenize, NUMBER, STRING, NAME, OP
from io import BytesIO
def decistmt(s):
"""Substitute Decimals for floats in a string of statements.
>>> from decimal import Decimal
>>> s = 'print(+21.3e-5*-.1234/81.7)'
>>> decistmt(s)
"print (+Decimal ('21.3e-5')*-Decimal ('.1234')/Decimal ('81.7'))"
The format of the exponent is inherited from the platform C library.
Known cases are "e-007" (Windows) and "e-07" (not Windows). Since
we're only showing 12 digits, and the 13th isn't close to 5, the
rest of the output should be platform-independent.
>>> exec(s) #doctest: +ELLIPSIS
-3.21716034272e-0...7
Output from calculations with Decimal should be identical across all
platforms.
>>> exec(decistmt(s))
-3.217160342717258261933904529E-7
"""
result = []
g = tokenize(BytesIO(s.encode('utf-8')).readline) # tokenize the string
for toknum, tokval, _, _, _ in g:
if toknum == NUMBER and '.' in tokval: # replace NUMBER tokens
result.extend([
(NAME, 'Decimal'),
(OP, '('),
(STRING, repr(tokval)),
(OP, ')')
])
else:
result.append((toknum, tokval))
return untokenize(result).decode('utf-8')
Beispiel für die Tokenisierung von der Kommandozeile. Das Skript
def say_hello():
print("Hello, World!")
say_hello()
wird zu folgender Ausgabe tokenisiert, wobei die erste Spalte der Bereich der Zeilen-/Spaltarkoordinaten ist, an denen das Token gefunden wird, die zweite Spalte der Name des Tokens und die letzte Spalte der Wert des Tokens (falls vorhanden) ist
$ python -m tokenize hello.py
0,0-0,0: ENCODING 'utf-8'
1,0-1,3: NAME 'def'
1,4-1,13: NAME 'say_hello'
1,13-1,14: OP '('
1,14-1,15: OP ')'
1,15-1,16: OP ':'
1,16-1,17: NEWLINE '\n'
2,0-2,4: INDENT ' '
2,4-2,9: NAME 'print'
2,9-2,10: OP '('
2,10-2,25: STRING '"Hello, World!"'
2,25-2,26: OP ')'
2,26-2,27: NEWLINE '\n'
3,0-3,1: NL '\n'
4,0-4,0: DEDENT ''
4,0-4,9: NAME 'say_hello'
4,9-4,10: OP '('
4,10-4,11: OP ')'
4,11-4,12: NEWLINE '\n'
5,0-5,0: ENDMARKER ''
Die exakten Token-Typnamen können mit der Option -e angezeigt werden
$ python -m tokenize -e hello.py
0,0-0,0: ENCODING 'utf-8'
1,0-1,3: NAME 'def'
1,4-1,13: NAME 'say_hello'
1,13-1,14: LPAR '('
1,14-1,15: RPAR ')'
1,15-1,16: COLON ':'
1,16-1,17: NEWLINE '\n'
2,0-2,4: INDENT ' '
2,4-2,9: NAME 'print'
2,9-2,10: LPAR '('
2,10-2,25: STRING '"Hello, World!"'
2,25-2,26: RPAR ')'
2,26-2,27: NEWLINE '\n'
3,0-3,1: NL '\n'
4,0-4,0: DEDENT ''
4,0-4,9: NAME 'say_hello'
4,9-4,10: LPAR '('
4,10-4,11: RPAR ')'
4,11-4,12: NEWLINE '\n'
5,0-5,0: ENDMARKER ''
Beispiel für die programmatische Tokenisierung einer Datei, die Unicode-Strings anstelle von Bytes mit generate_tokens() liest
import tokenize
with tokenize.open('hello.py') as f:
tokens = tokenize.generate_tokens(f.readline)
for token in tokens:
print(token)
Oder das direkte Lesen von Bytes mit tokenize()
import tokenize
with open('hello.py', 'rb') as f:
tokens = tokenize.tokenize(f.readline)
for token in tokens:
print(token)