Las herramientas que inspeccionan código fuente necesitan distinguir identificadores, números, strings, comentarios, operadores, indentación y marcadores de fin de entrada. El módulo token en Python proporciona las constantes numéricas y los mapas utilizados para representar esos elementos léxicos en tokenizers, parsers, depuradores, linters y transformadores de código.
Esta guía explica tok_name, EXACT_TOKEN_TYPES, ISTERMINAL(), ISNONTERMINAL() e ISEOF(), además de NAME, NUMBER, STRING, OP, indentación, f-strings y template strings. Complementa nuestros artículos sobre tokenize en Python, keyword, symtable, bytecode con dis y codeop.
Qué ofrece el módulo token
El archivo token.py asigna nombres simbólicos a categorías de tokens. Los valores numéricos son detalles de implementación y pueden cambiar entre versiones de Python. Por eso, una aplicación debe comparar con token.NAME y no con un entero copiado de otra ejecución.
import token
print(token.NAME)
print(token.NUMBER)
print(token.STRING)
print(token.tok_name[token.NAME])La documentación oficial de token explica que estas constantes representan nodos terminales de la gramática y reflejan definiciones utilizadas por el parser.
token y tokenize cumplen funciones diferentes
El módulo token define constantes y mappings. El módulo tokenize lee bytes o texto y produce registros con tipo, texto original, posición inicial, posición final y línea fuente.
import io
import token
import tokenize
codigo = b"total = precio + impuesto\n"
for elemento in tokenize.tokenize(io.BytesIO(codigo).readline):
nombre = token.tok_name.get(elemento.type, str(elemento.type))
print(nombre, elemento.string)Token es el vocabulario; tokenize es el scanner que genera elementos de ese vocabulario.
Usar tok_name
token.tok_name convierte códigos numéricos en nombres legibles.
for codigo, nombre in sorted(token.tok_name.items()):
print(codigo, nombre)Este mapping mejora logs, visualizadores y mensajes de error. Mostrar INDENT o DOUBLESTAR es mucho más útil que presentar únicamente un número.
El token NAME
NAME representa identificadores y palabras cuyo papel final depende del parser.
codigo = b"for item in items:\n print(item)\n"Según la API y las opciones del tokenizer, textos como for, item, in y print pueden aparecer inicialmente como nombres. Combina el texto con el módulo keyword para reconocer palabras reservadas y contextuales.
import keyword
if elemento.type == token.NAME:
if keyword.iskeyword(elemento.string):
categoria = "keyword"
elif keyword.issoftkeyword(elemento.string):
categoria = "soft keyword"
else:
categoria = "identificador"NUMBER conserva el texto original
NUMBER representa literales enteros, flotantes, complejos y números escritos en bases alternativas.
valores = b"10 3.14 0xff 1_000 2j\n"El token conserva el lexema. No convierte hexadecimal a entero ni elimina underscores. Deja la interpretación al parser o utiliza una conversión segura diseñada para el formato.
STRING
STRING representa strings y bytes convencionales. El texto incluye prefijos, comillas y escapes sin evaluarlos.
codigo = b"ruta = r'C:\\temp'\n"Esto permite que un formateador conserve el estilo de comillas. Cuando un literal confiable necesita convertirse, ast.literal_eval() es preferible a eval().
COMMENT
COMMENT identifica comentarios en la API pública de tokenize.
# comentario de configuración
limite = 10 # valor máximoEl parser ignora comentarios, pero formateadores, herramientas de documentación y refactorizadores deben preservarlos. Una AST por sí sola no conserva toda esta información.
NEWLINE y NL
NEWLINE termina una instrucción lógica. NL representa una ruptura física que no finaliza la expresión, por ejemplo dentro de paréntesis.
resultado = (
primero
+ segundo
)Las líneas internas generan NL; el cierre de la expresión produce NEWLINE. Esta diferencia ayuda a compiladores interactivos y formateadores.
INDENT y DEDENT
Python modela bloques mediante indentación. INDENT inicia un nivel más profundo y DEDENT regresa a un nivel exterior.
if activo:
ejecutar()
registrar()
finalizar()El token de indentación incluye los espacios o tabs originales. Los analizadores de estilo pueden inspeccionarlo, mientras la validación de ambigüedad pertenece al tokenizer y a herramientas como tabnanny.
ENCODING
tokenize.tokenize() lee bytes y comienza siempre con un token ENCODING.
with open("modulo.py", "rb") as archivo:
tokens = list(tokenize.tokenize(archivo.readline))
assert tokens[0].type == token.ENCODINGPython detecta la codificación mediante BOM o una declaración en las primeras líneas. La API basada en strings generate_tokens() no produce este marcador.
ENDMARKER
ENDMARKER señala el final de la entrada.
ultimo = tokens[-1]
assert ultimo.type == token.ENDMARKERLos consumidores de streams deben procesarlo para cerrar estado pendiente y confirmar que toda la entrada fue leída.
OP y tipos exactos
El módulo tokenize suele reportar operadores y delimitadores mediante la categoría genérica OP.
codigo = b"resultado += valor ** 2\n"Consulta TokenInfo.exact_type para distinguir +=, **, paréntesis, comas y otros símbolos.
for elemento in tokenize.tokenize(io.BytesIO(codigo).readline):
if elemento.type == token.OP:
print(elemento.string, token.tok_name[elemento.exact_type])El token genérico puede refinarse como PLUSEQUAL, DOUBLESTAR, LPAR u otra constante específica.
EXACT_TOKEN_TYPES
token.EXACT_TOKEN_TYPES mapea el texto del símbolo a su código exacto.
assert token.EXACT_TOKEN_TYPES["+"] == token.PLUS
assert token.EXACT_TOKEN_TYPES[":="] == token.COLONEQUAL
assert token.EXACT_TOKEN_TYPES["->"] == token.RARROWEl mapping resulta útil cuando una herramienta ya tiene la representación textual del operador.
Los operadores evolucionan
El módulo incluye constantes para paréntesis, corchetes, llaves, comas, dos puntos, operadores aritméticos, comparaciones, asignaciones compuestas, flechas de anotación y otros símbolos.
No mantengas una copia manual. Las versiones pueden añadir y retirar tokens, como ocurrió con COLONEQUAL, EXCLAMATION y constantes históricas de async.
Tokens de f-strings
Las versiones actuales exponen FSTRING_START, FSTRING_MIDDLE y FSTRING_END.
mensaje = f"Hola, {usuario.nombre}!"El inicio incluye el prefijo y la comilla de apertura. El texto literal se divide en partes intermedias, mientras las expresiones de sustitución usan tokens normales dentro de llaves.
Prueba cada versión soportada porque la gramática y tokenización de f-strings han evolucionado.
Template strings en Python 3.14
Python 3.14 añade TSTRING_START, TSTRING_MIDDLE y TSTRING_END para template string literals.
Un paquete compatible con versiones anteriores no debe importar estas constantes sin comprobación.
if hasattr(token, "TSTRING_START"):
soporta_tstrings = TrueLa detección de capacidades evita errores al importar el módulo en runtimes antiguos.
SOFT_KEYWORD
Existe una constante SOFT_KEYWORD para usos internos, pero tokenize normalmente entrega una palabra contextual como NAME.
if elemento.type == token.NAME and keyword.issoftkeyword(elemento.string):
print("soft keyword potencial")Solo el contexto sintáctico decide si la palabra tiene función especial. Analiza una AST cuando necesites certeza estructural.
ERRORTOKEN y excepciones
ERRORTOKEN puede representar entrada incorrecta en algunos casos. Sin embargo, tokenize también puede lanzar TokenError o producir tokens que el parser rechazará después.
try:
tokens = list(tokenize.generate_tokens(reader))
except tokenize.TokenError as error:
print("entrada incompleta o inválida", error)La ausencia de ERRORTOKEN no garantiza sintaxis válida. Usa compile() o ast.parse() después del análisis léxico.
TYPE_COMMENT y TYPE_IGNORE
TYPE_COMMENT y TYPE_IGNORE apoyan modos del compilador que reconocen comentarios de tipado.
resultado = cargar() # type: Resultado
ignorar() # type: ignoreEl tokenizer público no produce estos tipos en todas las configuraciones. Las herramientas de tipado suelen solicitar opciones específicas de AST.
ISTERMINAL()
token.ISTERMINAL(valor) informa si el código representa un token terminal.
assert token.ISTERMINAL(token.NAME)Esta función aparece principalmente en infraestructura que trabaja con gramáticas o árboles concretos del parser.
ISNONTERMINAL()
ISNONTERMINAL() verifica símbolos que representan reglas compuestas.
def clasificar(codigo):
if token.ISTERMINAL(codigo):
return "terminal"
if token.ISNONTERMINAL(codigo):
return "no terminal"
return "desconocido"La mayoría de herramientas modernas usa AST, pero los sistemas de parsing aún pueden necesitar esta distinción.
ISEOF()
ISEOF() identifica el marcador de fin de entrada sin comparar un número fijo.
assert token.ISEOF(token.ENDMARKER)La función mantiene la intención clara y reduce acoplamiento con detalles internos.
N_TOKENS
N_TOKENS informa cuántos tipos define el intérprete actual.
print(token.N_TOKENS)No lo utilices como formato persistente sin versión. La cantidad y los valores pueden cambiar.
Persistir nombres y versión
Cuando guardes resultados de análisis, registra el nombre simbólico y la versión del intérprete.
import platform
registro = {
"python": platform.python_version(),
"tipo": token.tok_name[elemento.type],
"texto": elemento.string,
}Un entero almacenado por una versión puede tener otro significado en una versión futura.
Formateadores y refactorizadores
Una transformación que debe preservar comentarios y espacios puede modificar tokens y reconstruir el código con tokenize.untokenize().
nuevos = []
for elemento in tokens:
if elemento.type == token.NAME and elemento.string == "nombre_antiguo":
elemento = elemento._replace(string="nombre_nuevo")
nuevos.append(elemento)
resultado = tokenize.untokenize(nuevos)Un renombrado correcto necesita análisis de scope. Combina tokens con symtable o AST para no modificar nombres sin relación.
Linters
Los linters pueden detectar operadores prohibidos o características concretas con exact_type.
if elemento.exact_type == token.COLONEQUAL:
reportar_walrus(elemento.start)Conserva posiciones y líneas originales para generar diagnósticos útiles.
Pruebas entre versiones
Ejecuta una matriz de CI con todos los runtimes soportados. Verifica constantes añadidas o eliminadas, f-strings, soft keywords y operadores exactos.
def test_potencia_exacta():
assert token.EXACT_TOKEN_TYPES["**"] == token.DOUBLESTARLa detección de recursos es más segura que importar un nombre inexistente.
Seguridad
Tokenizar no ejecuta el código, pero tampoco constituye una sandbox. Una entrada enorme o adversarial puede consumir recursos, y el código seguirá siendo peligroso si se ejecuta posteriormente.
Aplica límites de tamaño y tiempo. Nunca envíes entrada externa tokenizada directamente a eval() o exec().
Errores frecuentes
- Comparar tipos con números literales.
- Confundir
tokencontokenize. - Tratar todos los
OPcomo un único operador. - Ignorar
exact_type. - Confundir
NLyNEWLINE. - Esperar soft keywords como
SOFT_KEYWORD. - Persistir códigos sin versión.
- Ejecutar código solo porque se tokenizó correctamente.
Buenas prácticas
- Compara con constantes simbólicas.
- Usa
tok_nameen logs. - Consulta
exact_typepara operadores. - Conserva posiciones y líneas originales.
- Detecta características nuevas con seguridad.
- Prueba todas las versiones soportadas.
- Combina tokens con AST y tablas de símbolos.
- Limita entradas no confiables.
Conclusión
El módulo token en Python define el vocabulario utilizado para clasificar elementos léxicos del código fuente. Ofrece constantes legibles para nombres, números, strings, operadores, indentación, f-strings, template strings y marcadores internos.
Combinado con tokenize, keyword, AST y análisis de símbolos, permite construir herramientas precisas sin depender de números inestables. Utiliza nombres simbólicos, considera la versión objetivo y no confundas análisis sintáctico con ejecución segura.





