2 Stimmen

Python3.0 - tokenisieren und untokenisieren

Ich verwende etwas Ähnliches wie das folgende vereinfachte Skript zum Parsen von Python-Schnipseln aus einer größeren Datei:

import io
import tokenize

src = 'foo="bar"'
src = bytes(src.encode())
src = io.BytesIO(src)

src = list(tokenize.tokenize(src.readline))

for tok in src:
  print(tok)

src = tokenize.untokenize(src)

Obwohl der Code in python2.x nicht derselbe ist, verwendet er das gleiche Idiom und funktioniert einwandfrei. Wenn ich jedoch das obige Snippet mit Python 3.0 ausführe, erhalte ich diese Ausgabe:

(57, 'utf-8', (0, 0), (0, 0), '')
(1, 'foo', (1, 0), (1, 3), 'foo="bar"')
(53, '=', (1, 3), (1, 4), 'foo="bar"')
(3, '"bar"', (1, 4), (1, 9), 'foo="bar"')
(0, '', (2, 0), (2, 0), '')

Traceback (most recent call last):
  File "q.py", line 13, in <module>
    src = tokenize.untokenize(src)
  File "/usr/local/lib/python3.0/tokenize.py", line 236, in untokenize
    out = ut.untokenize(iterable)
  File "/usr/local/lib/python3.0/tokenize.py", line 165, in untokenize
    self.add_whitespace(start)
  File "/usr/local/lib/python3.0/tokenize.py", line 151, in add_whitespace
    assert row <= self.prev_row
AssertionError

Ich habe nach Hinweisen auf diesen Fehler und seine Ursachen gesucht, konnte aber keine finden. Was mache ich falsch und wie kann ich ihn beheben?

[Bearbeiten]

Nach partisann Die Beobachtung, dass das Anhängen eines Zeilenumbruchs an den Quelltext den Fehler behebt, hat mich dazu veranlasst, mit der Liste, die ich untoken wollte, herumzuspielen. Es scheint, dass die EOF Token führt zu einem Fehler, wenn ihm nicht unmittelbar ein Zeilenumbruch vorausgeht, so dass das Entfernen des Tokens den Fehler beseitigt. Das folgende Skript läuft ohne Fehler:

import io
import tokenize

src = 'foo="bar"'
src = bytes(src.encode())
src = io.BytesIO(src)

src = list(tokenize.tokenize(src.readline))

for tok in src:
  print(tok)

src = tokenize.untokenize(src[:-1])

3voto

Ivan Baldin Punkte 3091
src = 'foo="bar"\n'

Sie haben den Zeilenumbruch vergessen.

0voto

sykora Punkte 88704

Wenn Sie die Eingabe beschränken auf untokenize auf die ersten 2 Elemente der Token, scheint es zu funktionieren.

import io
import tokenize

src = 'foo="bar"'
src = bytes(src.encode())
src = io.BytesIO(src)

src = list(tokenize.tokenize(src.readline))

for tok in src:
  print(tok)

src = [t[:2] for t in src]
src = tokenize.untokenize(src)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X