Pregunta 1¿A qué módulo deberías recurrir para generar un token de restablecimiento de contraseña?
random y secrets — Eligiendo el tipo correcto de números aleatorios
Aprende los módulos random y secrets de Python desde cero. Cubre secuencias pseudoaleatorias reproducibles con random.choice / randint / shuffle / sample más seed, tokens criptográficamente seguros con secrets.token_hex / token_urlsafe, y cuándo usar uno frente al otro — con ejercicios prácticos ejecutables.
Este artículo cubre los dos módulos de números aleatorios de la biblioteca estándar. random proporciona valores pseudoaleatorios para pruebas, juegos y simulaciones (reproducibles con seed), y secrets proporciona valores impredecibles para contraseñas, tokens de restablecimiento y claves API (extraídos de la fuente aleatoria criptográfica del SO). Elegir el correcto para el trabajo es de lo que trata el resto del artículo.
Cómo difieren random y secrets
Ambos módulos devuelven números aleatorios, pero el mecanismo y los casos de uso son completamente diferentes. random está construido sobre el Mersenne Twister (un generador pseudoaleatorio ampliamente usado), y llamar a random.seed(valor) te permite reproducir la misma secuencia. secrets, por otro lado, extrae de la fuente aleatoria criptográfica del SO (como /dev/urandom), así que no hay concepto de `seed` y los valores son impredecibles en cada llamada.
Para casos como pruebas o juegos — «no pasa nada si el resultado se filtra» — usa random. Para contraseñas, tokens e ID de sesión — «si alguien predice el valor, tienes un incidente de seguridad» — usa secrets.
| Aspecto | random | secrets |
|---|---|---|
| Fuente | Mersenne Twister (algoritmo) | Fuente cripto del SO (/dev/urandom, etc.) |
| Reproducibilidad | Misma secuencia reproducible con seed | No reproducible (siempre diferente) |
| Velocidad | Rápido | Más lento (no es problema para el uso típico) |
| Mejor uso | Pruebas, juegos, simulaciones | Tokens, contraseñas, ID de sesión |
random — Lo básico (randint / uniform / choice)
Lo básico de random son tres cosas: un entero aleatorio / un float aleatorio / elegir un elemento de una lista. random.randint(min, max) devuelve un entero incluyendo ambos extremos, random.uniform(min, max) devuelve un float en el rango dado, y random.choice(lista) devuelve un elemento de la lista.
Empecemos sin seed y veamos cómo se comportan estas funciones básicas.
| Función | Retorno | Uso típico |
|---|---|---|
| random.randint(a, b) | Entero en [a, b] (ambos extremos incluidos) | Tiradas de dados, ID de prueba |
| random.uniform(a, b) | Float en [a, b] | Ruido, simulaciones probabilísticas |
| random.choice(seq) | Un elemento de la secuencia | Elegir un ítem de un menú |
random — Reproducibilidad por seed y operaciones sobre colecciones
Veamos ahora la reproducibilidad de pruebas con `random.seed` y las funciones de operación sobre colecciones (shuffle / sample). Después de llamar random.seed(N), la misma semilla siempre produce la misma secuencia. random.shuffle(lista) mezcla los elementos de la lista en su lugar, y random.sample(lista, k) devuelve una nueva lista de k elementos únicos extraídos de ella.
| Función | Retorno | Uso típico |
|---|---|---|
| random.seed(value) | None (inicializa el estado interno) | Pruebas reproducibles |
| random.shuffle(seq) | None (mezcla la lista original) | Aleatorizar el orden de una lista |
| random.sample(seq, k) | Nueva lista de k elementos únicos | Sortear k respondedores de una encuesta |
secrets — Aleatoriedad fuerte para seguridad
El módulo random de las secciones anteriores es un generador pseudoaleatorio para pruebas — si su estado interno se filtra, los siguientes valores pueden predecirse. Para cosas como tokens de restablecimiento de contraseña, claves API e ID de sesión — «si un atacante puede predecir el valor, tienes una vulnerabilidad» — elige el módulo `secrets`, que usa la fuente aleatoria criptográfica del SO.
secrets tiene una API mucho más pequeña que random — son sobre todo helpers que convierten bytes aleatorios en cadenas hex o URL-safe.
| Función | Retorno | Uso típico |
|---|---|---|
| secrets.token_bytes(n) | n bytes aleatorios | Claves cripto, tokens binarios internos |
| secrets.token_hex(n) | Cadena hex de longitud 2*n | ID de sesión de inicio |
| secrets.token_urlsafe(n) | Cadena URL-safe (estilo Base64) | Para incrustar en URLs de restablecimiento |
| secrets.choice(seq) | Un elemento de seq, criptográficamente | Cuando el orden de presentación no debe ser predecible |
| secrets.compare_digest(a, b) | True / False (resistente a ataques de tiempo) | Comparación de hash / token (usar en lugar de ==) |
Verificación de conocimientos
Responde cada pregunta una a una.
Pregunta 2Después de llamar random.seed(42) y luego random.randint(1, 100), ¿qué pasa si haces lo mismo otra vez?
Pregunta 3¿Cuál es la mejor opción cuando quieres que una lista mezclada aleatoriamente sea reproducible para pruebas?