Aprende leyendo en orden

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.

Cuándo usar random vs secrets
randomPseudoaleatorio reproduciblemisma secuencia con seedJuegos / pruebassimulacionessecretsCripto impredeciblesin seedTokens / contraseñasID de sesión
random te da valores pseudoaleatorios reproducibles — para pruebas y juegos. secrets extrae de la fuente criptográfica del SO valores impredecibles — para tokens y generación de contraseñas. Elige el correcto para el trabajo.
Aspectorandomsecrets
FuenteMersenne Twister (algoritmo)Fuente cripto del SO (/dev/urandom, etc.)
ReproducibilidadMisma secuencia reproducible con seedNo reproducible (siempre diferente)
VelocidadRápidoMás lento (no es problema para el uso típico)
Mejor usoPruebas, juegos, simulacionesTokens, 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.

Las funciones básicas de random
random.randint(a, b)→ entero en [a, b]random.uniform(a, b)→ float en [a, b]random.choice(lista)→ un elemento
randint es un entero aleatorio en rango (ambos extremos incluidos), uniform es un float aleatorio en rango, y choice toma un elemento de una lista. La forma de entrada y de retorno difiere para cada uno, así que elige según tu necesidad.
FunciónRetornoUso 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 secuenciaElegir un ítem de un menú

Prueba las tres funciones básicas de random. Los valores son distintos en cada ejecución, así que los verificamos por comprobaciones de rango y pertenencia en lugar de comparación exacta.

① Importa random.

② Genera un entero en 1〜100 con random.randint y guárdalo como n; genera un float en 0〜1 con random.uniform y guárdalo como f; elige un elemento de ["Apple", "Banana", "Cherry"] con random.choice y guárdalo como picked.

③ Imprime si n está en 1〜100, si f está en 0〜1, y si picked es miembro de la lista original, formateado como int range: True / False, float range: True / False, in list: True / False.

(Si tu código se ejecuta correctamente, aparecerá la explicación.)

Editor Python

Ejecutar el código para ver el resultado

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.

seed / shuffle / sample
random.seed(valor)→ fija estado internoreproduciblerandom.shuffle(lista)→ mezcla en su lugardevuelve Nonerandom.sample(lista, k)→ k items únicosnueva lista
seed(valor) fija el estado interno, así que la misma secuencia se repite. shuffle reorganiza la lista original en su lugar (devuelve None). sample devuelve una nueva lista de k elementos únicos (la original queda intacta).
FunciónRetornoUso 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 únicosSortear k respondedores de una encuesta

Confirma que un valor generado con seed 42 coincide con un valor generado de nuevo después de re-sembrar a 42.

① Importa random.

② Pon la semilla a 42, luego llama random.randint(1, 100) una vez y guárdalo como n1.

③ Pon la semilla de nuevo a 42, luego llama random.randint(1, 100) otra vez y guárdalo como n2.

④ Imprime n1 == n2 como reproducible: True.

Editor Python

Ejecutar el código para ver el resultado

Ve la diferencia entre shuffle (reorganiza la lista misma) y sample (devuelve una nueva lista).

① Pon la semilla a 7 y prepara cards = [1, 2, 3, 4, 5].

② Llama random.shuffle(cards) para reorganizar el contenido de cards en su lugar. Imprime cards reorganizado como after shuffle: ◯◯.

③ Re-siembra a 7, luego llama random.sample([1, 2, 3, 4, 5], 3) para elegir 3 elementos únicos, e imprime el resultado como picked 3: ◯◯.

Editor Python

Ejecutar el código para ver el resultado

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ónRetornoUso típico
secrets.token_bytes(n)n bytes aleatoriosClaves cripto, tokens binarios internos
secrets.token_hex(n)Cadena hex de longitud 2*nID 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áficamenteCuando 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 ==)

Genera tokens de seguridad con secrets y verifica su longitud y conjunto de caracteres. Los valores reales cambian en cada ejecución, así que verificamos propiedades como la longitud.

① Importa secrets.

② Genera un token hex de 16 bytes, imprime su longitud como hex length: ◯, y luego verifica que contiene solo caracteres en 0-9 y a-f como hex is hex only: True / False.

③ Genera un token URL-safe de 16 bytes e imprime su longitud como urlsafe length: ◯.

Editor Python

Ejecutar el código para ver el resultado
QUIZ

Verificación de conocimientos

Responde cada pregunta una a una.

Pregunta 1¿A qué módulo deberías recurrir para generar un token de restablecimiento de contraseña?

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?