tokenize
— Analisador léxico para código-fonte Python¶
Código-fonte: Lib/tokenize.py
O módulo tokenize
fornece um scanner léxico para código-fonte Python, implementado em Python. O scanner neste módulo retorna comentários como tokens também, tornando-o útil para implementar “pretty-printers”, incluindo colorizadores para exibições na tela.
Para simplificar o tratamento do fluxo de tokens, todos os tokens operadores e delimitadores e Ellipsis
são retornados usando o tipo de token genérico OP
. O tipo exato pode ser determinado verificando a propriedade exact_type
na tupla nomeada retornada de tokenize.tokenize()
.
Aviso
Observe que as funções neste módulo são projetadas apenas para analisar código Python sintaticamente válido (código que não levanta exceção quando analisado usando ast.parse()
). O comportamento das funções neste módulo é indefinido ao fornecer código Python inválido e pode mudar a qualquer momento.
Tokenizando entradas¶
O ponto de entrada principal é um gerador:
- tokenize.tokenize(readline)¶
O gerador
tokenize()
requer um argumento, readline, que deve ser um objeto chamável que fornece a mesma interface que o métodoio.IOBase.readline()
de objetos de arquivo. Cada chamada para a função deve retornar uma linha de entrada como bytes.O gerador produz tuplas de 5 elementos com estes membros: o tipo de token; a string de token; uma tupla de 2 elementos
(srow, scol)
de ints especificando a linha e a coluna onde o token começa na fonte; uma tupla de 2 elementos(erow, ecol)
de ints especificando a linha e a coluna onde o token termina na fonte; e a linha na qual o token foi encontrado. A linha passada (o último item da tupla) é a linha física. A tupla 5 elementos é retornada como uma tupla nomeada com os nomes dos campos:tipo string início fim linha
.A tupla nomeada retornada tem uma propriedade adicional chamada
exact_type
que contém o tipo exato do operador para tokensOP
. Para todos os outros tipos de token,exact_type
é igual ao campotype
da tupla nomeada.Alterado na versão 3.1: Adiciona suporte para tuplas nomeadas.
Alterado na versão 3.3: Adicionado suporte para
exact_type
.tokenize()
determina a codificação de origem do arquivo procurando por um BOM UTF-8 ou cookie de codificação, de acordo com PEP 263.
- tokenize.generate_tokens(readline)¶
Tokeniza uma fonte lendo strings unicode em vez de bytes.
Assim como
tokenize()
, o argumento readline é um chamável que retorna uma única linha de entrada. No entanto,generate_tokens()
espera que readline retorne um objeto str em vez de bytes.O resultado é um iterador produzindo tuplas nomeadas, exatamente como
tokenize()
. Ele não produz um tokenENCODING
.
Todas as constantes do módulo token
também são exportadas de tokenize
.
Outra função é fornecida para reverter o processo de tokenização. Isso é útil para criar ferramentas que tokenizam um script, modificam o fluxo de tokens e escrevem de volta o script modificado.
- tokenize.untokenize(iterable)¶
Converte tokens de volta para o código-fonte Python. O iterable deve retornar sequências com pelo menos dois elementos, o tipo de token e a string do token. Quaisquer elementos de sequência adicionais são ignorados.
O resultado é garantido para tokenizar de volta para corresponder à entrada, de modo que a conversão seja sem perdas e as viagens de ida e volta sejam garantidas. A garantia se aplica somente ao tipo de token e à sequência de tokens, pois o espaçamento entre os tokens (posições de coluna) pode mudar.
Retorna bytes, codificados usando o token
ENCODING
, que é a primeira sequência de tokens gerada portokenize()
. Se não houver nenhum token de codificação na entrada, ele retorna um str em vez disso.
tokenize()
precisa detectar a codificação dos arquivos fonte que ele tokeniza. A função que ele usa para fazer isso está disponível:
- tokenize.detect_encoding(readline)¶
A função
detect_encoding()
é usada para detectar a codificação que deve ser usada para decodificar um arquivo de origem Python. Ela requer um argumento, readline, da mesma forma que o geradortokenize()
.Ele chamará readline no máximo duas vezes e retornará a codificação usada (como uma string) e uma lista de todas as linhas (não decodificadas de bytes) que ele leu.
Ele detecta a codificação a partir da presença de um BOM UTF-8 ou um cookie de codificação conforme especificado em PEP 263. Se um BOM e um cookie estiverem presentes, mas discordarem, uma exceção
SyntaxError
será levantada. Observe que se o BOM for encontrado,'utf-8-sig'
será retornado como uma codificação.Se nenhuma codificação for especificada, o padrão
'utf-8'
será retornado.Use
open()
para abrir arquivos de código-fonte Python: ele usadetect_encoding()
para detectar a codificação do arquivo.
- tokenize.open(filename)¶
Abre um arquivo no modo somente leitura usando a codificação detectada por
detect_encoding()
.Adicionado na versão 3.2.
- exception tokenize.TokenError¶
Levantada quando uma docstring ou expressão que pode ser dividida em várias linhas não é concluída em nenhum lugar do arquivo, por exemplo:
"""Início da docstring
ou:
[1, 2, 3
Uso na linha de comando¶
Adicionado na versão 3.3.
O módulo tokenize
pode ser executado como um script a partir da linha de comando. É tão simples quanto:
python -m tokenize [-e] [nome-do-arquivo.py]
As seguintes opções são aceitas:
- -h, --help¶
mostra esta mensagem de ajuda e sai
- -e, --exact¶
exibe nomes de tokens usando o tipo exato
Se nome-de-arquivo.py
for especificado, seu conteúdo será tokenizado para stdout. Caso contrário, a tokenização será realizada em stdin.
Exemplos¶
Exemplo de um reescritor de script que transforma literais float em objetos Decimal:
from tokenize import tokenize, untokenize, NUMBER, STRING, NAME, OP
from io import BytesIO
def decistmt(s):
"""Substitui Decimals por floats em uma string de instruções.
>>> from decimal import Decimal
>>> s = 'print(+21.3e-5*-.1234/81.7)'
>>> decistmt(s)
"print (+Decimal ('21.3e-5')*-Decimal ('.1234')/Decimal ('81.7'))"
O formato do expoente é herdado da biblioteca da plataforma C. Casos
conhecidos são "e-007" (Windows) e "e-07" (não Windows). Como estamos
mostrando apenas 12 dígitos, e o 13º não está próximo de 5, o restante
da saída deve ser independente da plataforma.
>>> exec(s) #doctest: +ELLIPSIS
-3.21716034272e-0...7
A saída dos cálculos com Decimal deve ser idêntica em todas as
plataformas.
>>> 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')
Exemplo de tokenização a partir da linha de comando. O script:
def say_hello():
print("Hello, World!")
say_hello()
será tokenizado para a seguinte saída, onde a primeira coluna é o intervalo das coordenadas da linha/coluna onde o token é encontrado, a segunda coluna é o nome do token e a coluna final é o valor do token (se houver)
$ 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 ''
Os nomes exatos dos tipos de token podem ser exibidos usando a opção -e
:
$ 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 ''
Exemplo de tokenização de um arquivo programaticamente, lendo strings unicode em vez de bytes com generate_tokens()
:
import tokenize
with tokenize.open('hello.py') as f:
tokens = tokenize.generate_tokens(f.readline)
for token in tokens:
print(token)
Ou lendo bytes diretamente com tokenize()
:
import tokenize
with open('hello.py', 'rb') as f:
tokens = tokenize.tokenize(f.readline)
for token in tokens:
print(token)