The Rest You'll Meet — random, hashlib, uuid, secrets
~18 min · random, hashlib, uuid, secrets
Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
random — for non-security randomness
random.random(), random.randint(a, b), random.choice(seq), random.shuffle(list), random.sample(seq, k). Plenty for games, simulations, picking a sample from data. Seedable for reproducible tests via random.seed(42). Not cryptographically secure — don't use it for tokens, passwords, or anything an attacker shouldn't predict.
secrets — for security-sensitive randomness
secrets.token_hex(16), secrets.token_urlsafe(32), secrets.choice(seq). Same shape as random, but uses the OS's cryptographic RNG. Use this for session tokens, password reset codes, anything where guessability matters.
hashlib — content hashing
SHA-256 is the default everyday hash. hashlib.sha256(b"data").hexdigest(). Other algorithms exist but reach for SHA-256 unless you need otherwise. md5 and sha1 still work but are not collision-resistant — don't use them for security boundaries. Always hash bytes, not strings — encode first.
uuid — unique identifiers
uuid.uuid4() for random UUIDs (the most common case). uuid.uuid1() uses MAC + time (leaks both). Keep using uuid4 by default; the others have specific use cases. str(uuid.uuid4()) for the standard hyphenated string form.
Principle: The choice between random and secrets is "is this an attack surface or not?" If yes (auth, tokens, password reset, anti-CSRF), use secrets. If no (game logic, simulation, sampling), use random. Don't mix them up.
Code
random — for non-security uses·python
import random
random.seed(42) # reproducible
print(random.random()) # 0.6394...
print(random.randint(1, 100)) # 71
fruits = ["apple", "banana", "cherry", "date"]
print(random.choice(fruits)) # 'apple' (with seed 42)
print(random.sample(fruits, 2)) # ['banana', 'cherry']
random.shuffle(fruits)
print(fruits) # in random order
# Distributions
print(random.gauss(0, 1)) # normal distribution
print(random.uniform(10, 20)) # uniform in range
secrets — for cryptographic randomness·python
import secrets
# Token generation
print(secrets.token_hex(16)) # 32-char hex string (16 bytes)
print(secrets.token_urlsafe(32)) # URL-safe base64
print(secrets.token_bytes(8)) # 8 random bytes
# Random choice (cryptographically)
print(secrets.choice(["a", "b", "c"]))
# Comparison — random vs secrets for the same shape
import random
print("random:", random.randint(1, 100)) # predictable if seed known
print("secrets:", secrets.randbelow(100)) # not predictable
# Use secrets for: session tokens, password reset, API keys.
# Use random for: shuffling test data, picking a sample, simulations.
hashlib — content hashing·python
import hashlib
# SHA-256 is the everyday default
data = b"hello world"
h = hashlib.sha256(data)
print(h.hexdigest()) # 'b94d27b9934d3e08a52e52d7da7dab...'
print(h.digest()) # raw bytes
# Hashing a file in chunks (streaming for large files)
import pathlib
p = pathlib.Path("/etc/hostname")
h = hashlib.sha256()
with p.open("rb") as f:
while chunk := f.read(8192):
h.update(chunk)
print(h.hexdigest())
# Hashing a string — encode to bytes first
h = hashlib.sha256("안녕".encode("utf-8")).hexdigest()
print(h)
uuid — unique identifiers·python
import uuid
# uuid4 — random, the everyday choice
print(uuid.uuid4()) # ad8a0a2c-...
print(str(uuid.uuid4())) # standard hyphenated string
# uuid1 — based on MAC + time (leaks both — usually not what you want)
# uuid3, uuid5 — namespaced (deterministic given the same name)
# Common use: random IDs in databases
records = [{"id": str(uuid.uuid4()), "data": x} for x in ["a", "b", "c"]]
for r in records:
print(r)
shutil — high-level file operations·python
import shutil
import tempfile
from pathlib import Path
# Copy
src = Path("/etc/hostname")
dst = Path("/tmp/hostname-copy")
shutil.copy(src, dst)
print(dst.read_text(encoding="utf-8"))
dst.unlink()
# Move (rename)
f = Path("/tmp/source.txt")
f.write_text("hi", encoding="utf-8")
shutil.move(str(f), "/tmp/dest.txt")
Path("/tmp/dest.txt").unlink()
# Remove a directory tree (recursive)
with tempfile.TemporaryDirectory() as td:
sub = Path(td) / "nested" / "deeper"
sub.mkdir(parents=True)
(sub / "file.txt").write_text("hi", encoding="utf-8")
# shutil.rmtree(td) — would happen on context exit anyway
# Get terminal size, free disk space
print(shutil.get_terminal_size())
print(shutil.disk_usage("/"))
(a) Use secrets.token_urlsafe(24) to generate three session tokens and print them. (b) Hash the string "피파, 안녕" with SHA-256 (encode UTF-8 first) and print the hex digest. (c) Generate a random UUID4 and use it as a temp file name suffix in tempfile. (d) Use shutil.disk_usage('/') to print free space in human-readable form (GB).
Progress
Progress is local-only — sign in to sync across devices.