tokenize en Python: analiza código fuente

Publicado el: 05/08/2026
Tempo de leitura: 7 minutos
Código fuente en pantalla que representa análisis con tokenize en Python

Los linters, formateadores, analizadores de seguridad, editores y herramientas educativas necesitan comprender código Python sin ejecutarlo. El módulo tokenize en Python convierte el texto fuente en una secuencia de unidades léxicas como nombres, números, operadores, cadenas, comentarios, saltos de línea e indicadores de indentación. Esta capa se encuentra entre el archivo original y estructuras de nivel superior como el árbol de sintaxis abstracta.

En esta guía aprenderás a leer tokens, respetar la codificación, inspeccionar posiciones exactas, localizar comentarios, reconstruir código, tratar entradas incompletas y combinar tokenize con AST y tablas de símbolos. El contenido complementa nuestros artículos sobre inspect, symtable, dis, expresiones regulares y Ruff.

Qué representa un token

Un token es una unidad léxica reconocida por el analizador. La palabra def, el nombre de una función, los paréntesis, un número, una cadena y un comentario son tokens diferentes. A diferencia de una búsqueda de texto simple, la tokenización comprende cadenas multilínea, caracteres escapados, comentarios, indentación y operadores compuestos.

import tokenize
from io import BytesIO

codigo = b"cantidad = 10  # valor inicial\n"
for elemento in tokenize.tokenize(BytesIO(codigo).readline):
    print(elemento)

La API basada en bytes es importante porque Python debe determinar la codificación antes de decodificar el archivo.

Campos de TokenInfo

Cada elemento generado es un TokenInfo. Contiene el tipo, el texto exacto, la posición inicial, la posición final y la línea física original.

for elemento in tokenize.tokenize(BytesIO(codigo).readline):
    print(elemento.type, elemento.string, elemento.start, elemento.end)

Las posiciones se expresan como (línea, columna). Las líneas empiezan en uno y las columnas en cero. Un editor o diagnóstico puede usar estas coordenadas para señalar una región exacta.

Nombres legibles de los tipos

El número del tipo se convierte en un nombre legible mediante token.tok_name.

import token

for elemento in tokenize.tokenize(BytesIO(codigo).readline):
    print(token.tok_name[elemento.type], repr(elemento.string))

Entre los valores comunes están ENCODING, NAME, OP, NUMBER, STRING, COMMENT, NEWLINE, INDENT, DEDENT y ENDMARKER.

Detectar la codificación

Los archivos Python pueden declarar su codificación en una de las primeras dos líneas. detect_encoding() aplica las mismas reglas que el intérprete.

with open("aplicacion.py", "rb") as archivo:
    codificacion, lineas = tokenize.detect_encoding(archivo.readline)

print(codificacion)

La documentación oficial de tokenize describe cómo se procesan el BOM UTF-8 y el comentario de codificación. Si ambos se contradicen, se genera un error.

Abrir archivos Python correctamente

tokenize.open() detecta la codificación y devuelve un flujo de texto.

with tokenize.open("aplicacion.py") as archivo:
    fuente = archivo.read()

Es preferible a imponer UTF-8 cuando una herramienta debe procesar proyectos antiguos o mixtos. En proyectos nuevos, UTF-8 sigue siendo la opción recomendada.

Tokenizar una cadena existente

Cuando el código ya está decodificado, generate_tokens() acepta una función readline que devuelve texto.

from io import StringIO

fuente = "total = precio * cantidad\n"
for elemento in tokenize.generate_tokens(StringIO(fuente).readline):
    print(elemento)

Esta variante no emite el token ENCODING. Usa la API de bytes para archivos y la API textual cuando la codificación ya fue resuelta.

Encontrar comentarios

Los comentarios aparecen como tokens COMMENT. No es necesario buscar manualmente el carácter #.

comentarios = []
for elemento in tokenize.generate_tokens(StringIO(fuente).readline):
    if elemento.type == token.COMMENT:
        comentarios.append((elemento.start, elemento.string))

Una expresión regular podría confundir un numeral dentro de una cadena con un comentario. El tokenizador distingue esos casos.

Recopilar identificadores

Los tokens NAME pueden formar índices, métricas o ejercicios educativos.

nombres = {
    elemento.string
    for elemento in tokenize.generate_tokens(StringIO(fuente).readline)
    if elemento.type == token.NAME
}

El conjunto incluye palabras reservadas. El módulo keyword permite excluirlas.

import keyword

identificadores = {n for n in nombres if not keyword.iskeyword(n)}

Esta lista no indica qué ámbito posee cada nombre. Para resolver ámbitos, combina el resultado con AST y symtable.

Tokens de indentación

Python emite INDENT y DEDENT cuando cambia el nivel de un bloque.

fuente = "def doble(valor):\n    return valor * 2\n"
for elemento in tokenize.generate_tokens(StringIO(fuente).readline):
    if elemento.type in {token.INDENT, token.DEDENT}:
        print(token.tok_name[elemento.type], repr(elemento.string))

Estos tokens permiten construir visualizaciones de bloques, estadísticas de indentación y diagnósticos más fiables que contar espacios sin comprender las líneas lógicas.

NEWLINE y NL

NEWLINE termina una instrucción lógica. NL representa un salto físico que no termina la instrucción, por ejemplo dentro de paréntesis, corchetes o llaves.

valores = [
    1,
    2,
]

Los saltos internos generan NL. Los formateadores y herramientas que conservan comentarios deben distinguir ambos tipos.

Tipo exacto de operadores

La mayoría de signos se emiten con el tipo general OP. La propiedad exact_type identifica el operador concreto.

for elemento in tokenize.generate_tokens(StringIO("valor += 1\n").readline):
    if elemento.type == token.OP:
        print(token.tok_name[elemento.exact_type])

Así puedes diferenciar asignación, asignación aumentada, flechas, delimitadores y operadores aritméticos sin mantener una tabla manual.

Reconstruir código

untokenize() vuelve a crear texto o bytes a partir de tokens.

elementos = list(tokenize.tokenize(BytesIO(codigo).readline))
reconstruido = tokenize.untokenize(elementos)
print(reconstruido)

La garantía documentada se refiere a la equivalencia de tipos y textos al tokenizar de nuevo. El espaciado exacto puede cambiar.

Una transformación sencilla

Es posible sustituir tokens NAME seleccionados y reconstruir el resultado.

resultado = []
lector = StringIO("valor = valor + 1\n")
for elemento in tokenize.generate_tokens(lector.readline):
    if elemento.type == token.NAME and elemento.string == "valor":
        elemento = elemento._replace(string="contador")
    resultado.append(elemento)

nuevo_codigo = tokenize.untokenize(resultado)

Esto es un reemplazo léxico, no una refactorización completa. Puede renombrar variables distintas que comparten el mismo texto en ámbitos diferentes.

Tratar TokenError

Las construcciones incompletas pueden generar TokenError. Algunos ejemplos son una cadena triple sin cerrar o paréntesis abiertos al final del archivo.

try:
    list(tokenize.generate_tokens(StringIO("texto = '''abierto").readline))
except tokenize.TokenError as error:
    mensaje, posicion = error.args
    print(mensaje, posicion)

Un buen diagnóstico debe mostrar la posición, conservar el código original y evitar correcciones automáticas sin contexto.

Errores de indentación

Una indentación inválida puede producir IndentationError. Las herramientas deben capturar ambos tipos de fallo.

try:
    elementos = list(tokenize.generate_tokens(StringIO(fuente).readline))
except (tokenize.TokenError, IndentationError) as error:
    print(f"Código inválido: {error}")

Tokenizar no valida toda la sintaxis

Un archivo puede tokenizarse y aun contener una gramática inválida. Usa ast.parse() para validar la sintaxis.

import ast

ast.parse(fuente)

Tokenize responde qué unidades léxicas existen. AST explica cómo forman expresiones, instrucciones, funciones, clases y control de flujo.

Combinar tokens y AST

Los nodos AST ofrecen estructura semántica, pero normalmente no conservan todos los comentarios y detalles de formato. Los tokens retienen comentarios y posiciones exactas. Los formateadores, codemods y analizadores suelen utilizar ambas representaciones.

Para determinar el ámbito de los nombres y las closures, añade symtable. Para objetos en ejecución, inspect es apropiado, pero importar código no confiable implica riesgo.

Seguridad y límites

Tokenizar no ejecuta el código, lo que es más seguro que importarlo. Sin embargo, archivos enormes o entradas adversarias pueden consumir memoria y CPU. Limita tamaño, longitud de líneas, anidamiento, cantidad de archivos y tiempo de procesamiento.

Al modificar archivos, escribe primero en una ubicación temporal. Tokeniza y analiza el resultado, ejecuta pruebas y sustituye el original de forma atómica.

Crear un resumen de tokens

from collections import Counter

def resumir(fuente):
    conteo = Counter()
    lector = StringIO(fuente).readline
    for elemento in tokenize.generate_tokens(lector):
        conteo[token.tok_name[elemento.type]] += 1
    return dict(conteo)

El diccionario puede mostrar la cantidad de comentarios, cadenas, operadores, nombres, líneas lógicas y cambios de indentación.

Uso desde la terminal

El módulo incluye una interfaz de línea de comandos:

python -m tokenize aplicacion.py

La opción -e muestra los nombres exactos de los operadores. Es útil para aprender y depurar transformaciones.

Errores frecuentes

  • Buscar comentarios con regex y coincidir con numerales dentro de cadenas.
  • Ignorar ENCODING al trabajar con bytes.
  • Tratar NL y NEWLINE como equivalentes.
  • Usar reemplazo léxico como refactorización consciente de ámbitos.
  • Suponer que untokenize conserva todos los espacios.
  • Importar código cuando el análisis estático es suficiente.
  • Procesar entradas no confiables sin límites.

Buenas prácticas

  • Lee archivos como bytes con tokenize.tokenize.
  • Usa tokenize.open para obtener texto decodificado.
  • Convierte tipos mediante el módulo token.
  • Usa exact_type para signos y operadores.
  • Combina tokens, AST y symtable según la tarea.
  • Valida el resultado antes de sustituir archivos.
  • Prueba Unicode, cadenas multilínea, comentarios y entradas incompletas.

Conclusión

El módulo tokenize en Python ofrece una visión precisa del código fuente en el nivel léxico. Identifica nombres, números, cadenas, comentarios, operadores, saltos de línea e indentación, y conserva coordenadas útiles para editores y diagnósticos.

Utilízalo para análisis estático ligero, extracción de comentarios, métricas, enseñanza y transformaciones controladas. Combínalo con AST y symtable para comprender estructura y ámbitos. Con codificación correcta, límites de recursos, tratamiento de errores y validación posterior, puedes crear herramientas fiables sin ejecutar los archivos analizados.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Monitor con código binario que representa análisis de opcodes pickle con pickletools en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    pickletools en Python: analiza pickles

    Aprende pickletools en Python para desmontar pickles, analizar opcodes y optimizar flujos sin ejecutar datos no confiables.

    Ler mais

    Tempo de leitura: 6 minutos
    05/08/2026
    Desarrollador trabajando en automatización de build y compilación de directorios con compileall en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    compileall en Python: compila directorios

    Aprende compileall en Python para compilar directorios, generar pyc en paralelo, filtrar rutas y controlar optimización e invalidación.

    Ler mais

    Tempo de leitura: 6 minutos
    04/08/2026
    Monitor con código binario que representa generación de archivos pyc con py_compile en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    py_compile en Python: genera archivos pyc

    Aprende py_compile en Python para generar archivos pyc, validar sintaxis y controlar optimización e invalidación por timestamp o hash.

    Ler mais

    Tempo de leitura: 6 minutos
    04/08/2026
    Editor de código que representa corrección de tabs y espacios con tabnanny en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    tabnanny en Python: corrige la indentación

    Aprende tabnanny en Python para detectar tabs y espacios ambiguos, revisar proyectos y evitar TabError e IndentationError.

    Ler mais

    Tempo de leitura: 7 minutos
    04/08/2026
    Código fuente y sintaxis que representan análisis léxico con tokenize en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    tokenize en Python: analiza código fuente

    Aprende tokenize en Python para analizar tokens, comentarios, encoding, posiciones y reconstruir código fuente con seguridad.

    Ler mais

    Tempo de leitura: 6 minutos
    04/08/2026
    Terminal de programación que representa compilación de entradas interactivas con codeop en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    codeop en Python: compila entradas interactivas

    Aprende codeop en Python para detectar entradas completas, compilar comandos de REPL y conservar __future__ con seguridad.

    Ler mais

    Tempo de leitura: 7 minutos
    04/08/2026