Módulo random de Python
Aprende el módulo random de Python: genera números aleatorios, haz selecciones ponderadas, baraja secuencias, usa semillas para reproducibilidad y aleatoriedad criptográfica.
El módulo random integrado de Python genera números pseudoaleatorios y realiza selecciones aleatorias. Se basa en el algoritmo Mersenne Twister, que produce secuencias pseudoaleatorias de alta calidad adecuadas para simulaciones, juegos, muestreo y pruebas — pero no para propósitos sensibles a la seguridad como la generación de contraseñas o claves criptográficas. Este capítulo cubre:
- Generación de floats, enteros y rangos aleatorios
- Selección de elementos aleatorios:
choice,choices,sample - Barajado de secuencias en el lugar con
shuffle - Uso de semillas para resultados reproducibles
- Distribuciones continuas:
uniform,gauss,triangular - Cuándo usar
secretsen lugar derandom
No se necesita instalación — basta con import random.
Importar el módulo
import randomTodos los ejemplos a continuación asumen que esta importación está en el ámbito. También puedes importar funciones individuales para evitar el prefijo random., aunque el prefijo deja claro de dónde proviene cada función:
from random import randint, choice, shuffleGenerar floats aleatorios
random()
random.random() devuelve un float en [0.0, 1.0) — incluye 0.0 pero nunca alcanza 1.0.
import random
print(random.random()) # e.g. 0.6394267984578837
print(random.random()) # e.g. 0.025010755222666936El valor cambia en cada llamada porque el generador avanza su estado interno.
uniform(a, b)
random.uniform(a, b) devuelve un float N tal que a <= N <= b:
import random
random.seed(42)
print(random.uniform(1.5, 10.5)) # 7.254841186120954
print(random.uniform(-1.0, 1.0)) # e.g. -0.82 (some float in [-1, 1])A diferencia de random(), uniform te permite especificar ambos extremos del rango, y el límite superior puede ser devuelto.
Generar enteros aleatorios
randint(a, b)
random.randint(a, b) devuelve un entero aleatorio N tal que a <= N <= b. Ambos extremos son inclusivos:
import random
random.seed(42)
die = random.randint(1, 6)
print(die) # 6Esta es la forma más común de simular tiradas de dados, robos de cartas o cualquier rango entero discreto.
randrange(start, stop[, step])
random.randrange imita range() de Python — stop es exclusivo y puedes especificar un paso:
import random
random.seed(42)
# Pick an even number from 0 to 98 (0, 2, 4, ..., 98)
print(random.randrange(0, 100, 2)) # e.g. a random even integer
# Pick a multiple of 5 from 0 to 95
random.seed(42)
print(random.randrange(0, 100, 5)) # 15Cuando necesitas enteros aleatorios de un rango que no comienza en 0, o que requiere un paso, randrange es más expresivo que randint.
getrandbits(k)
random.getrandbits(k) devuelve un entero no negativo aleatorio con exactamente k bits aleatorios:
import random
random.seed(42)
print(random.getrandbits(8)) # 163 (an integer in 0..255)
print(random.getrandbits(16)) # an integer in 0..65535Esto es útil cuando necesitas enteros aleatorios más grandes que los que se obtienen con randint, o cuando trabajas a nivel de bits.
Elegir de secuencias
choice(seq)
random.choice(seq) elige un elemento aleatorio de una secuencia no vacía. Funciona con listas, tuplas y strings:
import random
random.seed(42)
fruits = ['apple', 'banana', 'cherry']
print(random.choice(fruits)) # cherry
random.seed(42)
print(random.choice('ABCDE')) # A (picks one character)Si la secuencia está vacía, se lanza un IndexError.
choices(population, weights=None, k=1)
random.choices elige k elementos con reemplazo (el mismo elemento puede aparecer más de una vez). Puedes sesgar la selección con weights:
import random
colors = ['red', 'blue', 'green']
# Equal probability — each run may differ
print(random.choices(colors, k=3))
# e.g. ['blue', 'red', 'red']
# Weighted: green is 3× more likely than red, blue is 2×
random.seed(42)
print(random.choices(colors, weights=[1, 2, 3], k=4))
# ['green', 'red', 'blue', 'blue']choices siempre devuelve una lista, incluso cuando k=1. El argumento weights es relativo — [1, 2, 3] produce la misma distribución que [10, 20, 30].
sample(population, k)
random.sample elige k elementos sin reemplazo — cada elemento solo puede aparecer una vez en el resultado. No modifica la secuencia original:
import random
random.seed(42)
# Pick 4 unique numbers from 0-9
print(random.sample(range(10), 4)) # [1, 0, 4, 9]
# Simulate a lottery: 6 unique numbers from 1-49
random.seed(7)
ticket = sorted(random.sample(range(1, 50), 6))
print(ticket) # [4, 5, 10, 21, 26, 42]Si k es mayor que el tamaño de la población, random.sample lanza un ValueError:
import random
try:
random.sample([1, 2, 3], 5)
except ValueError as e:
print(e) # Sample larger than population or is negativechoices vs sample de un vistazo:
choices | sample | |
|---|---|---|
| Reemplazo | Sí | No |
| Resultados duplicados | Posible | Nunca |
| Modifica el original | No | No |
| Admite pesos | Sí | No (usa choices) |
Barajar secuencias
random.shuffle(seq) baraja la lista en el lugar y devuelve None. La lista original es modificada:
import random
random.seed(42)
deck = [1, 2, 3, 4, 5]
random.shuffle(deck)
print(deck) # [4, 2, 3, 5, 1] (original list is modified)Si necesitas una copia barajada sin tocar el original, usa random.sample:
import random
random.seed(42)
original = [1, 2, 3, 4, 5]
shuffled = random.sample(original, len(original))
print(original) # [1, 2, 3, 4, 5] (unchanged)
print(shuffled) # [4, 2, 3, 5, 1]Semillas para resultados reproducibles
Por defecto, el módulo random se inicializa con la hora del sistema (o os.urandom()), por lo que cada ejecución produce valores diferentes. Llamar a random.seed() con un valor fijo bloquea la secuencia para obtener un resultado idéntico cada vez — esencial para depuración, pruebas unitarias y simulaciones reproducibles:
import random
random.seed(42)
print(random.random()) # 0.6394267984578837
print(random.randint(1, 10)) # 1
print(random.choice(['a', 'b', 'c'])) # c
# Reset to the same seed — identical sequence
random.seed(42)
print(random.random()) # 0.6394267984578837 (same as before)
print(random.randint(1, 10)) # 1
print(random.choice(['a', 'b', 'c'])) # crandom.seed() acepta un entero, una string, un float, bytes o None (que reinicia la semilla desde el sistema). La inicialización con semilla es una operación global — afecta todas las llamadas posteriores en el mismo programa, por lo que debes establecer la semilla una sola vez al inicio de un bloque reproducible.
Generación de datos de prueba reproducibles
import random
random.seed(999)
test_scores = [round(random.uniform(0, 100), 2) for _ in range(5)]
print(test_scores) # [78.13, 8.01, 87.25, 57.38, 49.06]Cada ejecución con seed(999) produce exactamente la misma lista, lo que resulta útil para pruebas unitarias que comprueban valores específicos.
Distribuciones continuas
El módulo random incluye varias distribuciones de probabilidad continuas, útiles en simulaciones y modelado estadístico.
uniform(a, b)
Ya cubierto anteriormente — una distribución plana donde cada valor en [a, b] es igualmente probable.
triangular(low, high, mode)
Devuelve un float de una distribución triangular donde mode es el valor más frecuente:
import random
random.seed(42)
# Most values cluster near 5, between 0 and 10
t = random.triangular(0, 10, 5)
print(t) # 5.753983033817951Útil cuando conoces el mínimo, el máximo y el valor más probable pero no la distribución exacta — común en estimación de proyectos y modelado de riesgos.
gauss(mu, sigma)
Devuelve un float de una distribución gaussiana (normal) con media mu y desviación estándar sigma:
import random
random.seed(42)
# Heights in cm: mean 170, std 10
heights = [round(random.gauss(170, 10), 1) for _ in range(5)]
print(heights) # [168.6, 168.3, 168.9, 177.0, 168.7]random.normalvariate(mu, sigma) es equivalente pero seguro para hilos; usa normalvariate en programas con múltiples hilos.
expovariate(lambd)
Devuelve un float de una distribución exponencial, donde lambd es 1 / media. Útil para modelar el tiempo entre eventos (por ejemplo, llegadas de clientes, paquetes de red):
import random
random.seed(42)
# Mean inter-arrival time = 5 minutes; lambd = 1/5
wait = random.expovariate(1 / 5)
print(round(wait, 2)) # 5.1 (minutes until next arrival)Ejemplos prácticos
Simular 60 tiradas de dados
import random
random.seed(42)
counts = {face: 0 for face in range(1, 7)}
for _ in range(60):
counts[random.randint(1, 6)] += 1
print(counts)
# {1: 15, 2: 10, 3: 8, 4: 7, 5: 10, 6: 10}Con más tiradas, la distribución se aproxima a la probabilidad teórica de 1/6 para cada cara.
Elegir un equipo aleatorio
import random
random.seed(42)
players = ['Alice', 'Bob', 'Carol', 'Dave', 'Eve', 'Frank']
random.shuffle(players)
team_a = players[:3]
team_b = players[3:]
print('Team A:', team_a)
print('Team B:', team_b)Contraseña aleatoria simple
Para contextos sin seguridad (demos, tokens descartables), random.choices funciona bien:
import random
import string
random.seed(42)
chars = string.ascii_letters + string.digits
password = ''.join(random.choices(chars, k=12))
print(password) # NbrnTP3fAbnFPara contraseñas o tokens de usuario reales, usa el módulo secrets en su lugar (ver más abajo).
Cuándo usar secrets en lugar de random
El módulo random no es criptográficamente seguro. Un atacante que observe suficiente salida puede predecir valores futuros. Para cualquier cosa sensible a la seguridad, usa el módulo secrets (Python 3.6+), que obtiene valores de la fuente aleatoria criptográfica del sistema operativo:
import secrets
# Cryptographically secure random integer in [0, 100)
print(secrets.randbelow(100))
# Secure random token for a password-reset link (URL-safe base64)
token = secrets.token_urlsafe(32)
print(token) # e.g. 'gIg9XzExxFkHLAH9JCK8Zxb1aBEFZ...'
# Secure random hex string for an API key
api_key = secrets.token_hex(16)
print(api_key) # e.g. 'a3f1c2d4e5b6...'Regla general: si estás generando tokens, IDs de sesión, contraseñas o cualquier valor que un adversario no debe poder adivinar, usa secrets. Usa random para todo lo demás (juegos, simulaciones, datos de prueba, muestreo).
Referencia rápida
| Función | Descripción | Devuelve |
|---|---|---|
random.random() | Float en [0.0, 1.0) | float |
random.uniform(a, b) | Float en [a, b] | float |
random.randint(a, b) | Entero en [a, b] (ambos inclusivos) | int |
random.randrange(start, stop[, step]) | Entero de range(start, stop, step) | int |
random.getrandbits(k) | Entero no negativo con k bits aleatorios | int |
random.choice(seq) | Un elemento aleatorio | tipo del elemento |
random.choices(pop, weights, k) | k elementos con reemplazo | list |
random.sample(pop, k) | k elementos sin reemplazo | list |
random.shuffle(seq) | Baraja la lista en el lugar | None |
random.seed(a) | Establece la semilla aleatoria | None |
random.gauss(mu, sigma) | Variante gaussiana (normal) | float |
random.normalvariate(mu, sigma) | Variante normal (segura para hilos) | float |
random.triangular(low, high, mode) | Variante de distribución triangular | float |
random.expovariate(lambd) | Variante de distribución exponencial | float |
Capítulos relacionados
- Python Math — funciones matemáticas y constantes
- Python Modules — cómo importar y organizar módulos
- Python Numbers — tipos entero, float y complejo
- Python Lists — trabajar con secuencias ordenadas
- Python For Loops — iterar para generar datos aleatorios
- Python Try Except — manejar errores como
ValueErrordesample