How to Generate a Random String in Python
Generate a Python string with a chosen alphabet and exact length. Learn when to use random, when to use secrets, and how to create URL-safe tokens.
To generate a random string of an exact length in Python, choose an alphabet and select one character at a time. Use random.choice for ordinary sample data, and secrets.choice when the string is a password, token, or other security-sensitive value.
import secrets
import string
alphabet = string.ascii_letters + string.digits
length = 16
value = ''.join(secrets.choice(alphabet) for _ in range(length))
print(value)
This produces exactly 16 characters from uppercase letters, lowercase letters, and digits. The method you choose matters: Python’s random module is deterministic and unsuitable for cryptographic purposes, while secrets is designed for security-sensitive random values. See the official documentation for random and secrets.
1. Choose the right generator
| Use case | Method | Why |
|---|---|---|
| Fixtures, sample data, simulations | random.choice |
Convenient, but deterministic and not for secrets. |
| Passwords, authentication tokens, secret identifiers | secrets.choice |
Security-oriented selection from your chosen alphabet. |
| URL-safe token where approximate length is acceptable | secrets.token_urlsafe |
Returns URL-safe encoded random bytes. |
| Hexadecimal token | secrets.token_hex |
Each random byte becomes two hexadecimal characters. |
Do not use random.randbytes to create security tokens. Python’s random documentation directs users to secrets.token_bytes for security-sensitive bytes.
2. Generate an ordinary random string
For non-security uses, define the allowed characters and select from that alphabet repeatedly:
import random
import string
alphabet = string.ascii_letters + string.digits
length = 16
value = ''.join(random.choice(alphabet) for _ in range(length))
print(value)
string.ascii_letters contains ASCII uppercase and lowercase letters, and string.digits contains the decimal digits. To generate lowercase alphanumeric text instead:
import random
import string
alphabet = string.ascii_lowercase + string.digits
value = ''.join(random.choice(alphabet) for _ in range(12))
print(value)
For reproducible simulations, seed the generator deliberately:
import random
import string
rng = random.Random(2026)
alphabet = string.ascii_letters + string.digits
value = ''.join(rng.choice(alphabet) for _ in range(16))
print(value)
A seeded generator is useful when you want the same sequence again, such as in a repeatable simulation. Do not use a predictable seed or this generator for credentials, reset links, or other secrets.
3. Generate a secure string of an exact length
Use secrets.choice with the alphabet you need. This retains both the exact output length and the exact set of allowed characters:
import secrets
import string
alphabet = string.ascii_letters + string.digits
length = 32
secret_value = ''.join(secrets.choice(alphabet) for _ in range(length))
print(secret_value)
For a custom alphabet, provide a string or another sequence of selectable characters:
import secrets
alphabet = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'
code = ''.join(secrets.choice(alphabet) for _ in range(8))
print(code)
This example omits characters that can be confused visually, such as zero and the letter O. The output remains exactly eight characters and uses only the supplied alphabet.
Understand the size of the choice space
If every character is selected uniformly from an alphabet of size A, a length-L string has AL possible values. For example, a 16-character alphanumeric string using 62 characters has 6216 possible strings. This is the size of the output space; it should not be treated as a universal security guarantee. Choose length and entropy based on the application’s threat model and requirements.
4. Generate a URL-safe token
For a token intended to be placed in a URL, use secrets.token_urlsafe:
import secrets
token = secrets.token_urlsafe(32)
print(token)
The argument is a count of random bytes, not a requested number of output characters. The bytes are Base64-encoded into URL-safe text; the result averages about 1.3 characters per input byte, so its exact character count is not the same as the argument. Use repeated secrets.choice instead when exact output length and alphabet are requirements.
For hexadecimal output, use token_hex:
import secrets
token = secrets.token_hex(16)
print(token)
Sixteen random bytes produce 32 hexadecimal characters. As with URL-safe tokens, the argument measures bytes rather than output characters.
5. Require character classes in a password
If a password policy requires at least one character from specific classes, generate candidates securely and reject any that do not meet the policy. Python’s secrets documentation demonstrates this retry approach. Here is a runnable example requiring lowercase, uppercase, and at least one digit:
import secrets
import string
alphabet = string.ascii_letters + string.digits
length = 16
while True:
password = ''.join(secrets.choice(alphabet) for _ in range(length))
if (any(c.islower() for c in password)
and any(c.isupper() for c in password)
and any(c.isdigit() for c in password)):
break
print(password)
For complex policies, another approach is to securely select one character from each required class, fill the remaining positions from the combined alphabet, then securely shuffle the result. This avoids repeated candidate generation, but the shuffle must also use a security-oriented source such as secrets.SystemRandom().shuffle:
import secrets
import string
rng = secrets.SystemRandom()
lower = string.ascii_lowercase
upper = string.ascii_uppercase
digits = string.digits
alphabet = lower + upper + digits
length = 16
if length < 3:
raise ValueError('length must allow all three required classes')
chars = [secrets.choice(lower), secrets.choice(upper), secrets.choice(digits)]
chars.extend(secrets.choice(alphabet) for _ in range(length - len(chars)))
rng.shuffle(chars)
password = ''.join(chars)
print(password)
Generating a password does not solve password storage. Applications should store passwords using a salted, strong one-way password hash, not in recoverable form; consult a password-hashing library and your platform’s security guidance for that separate task.
6. Make a reusable function with input checks
A small helper makes the length and alphabet explicit. Reject an empty alphabet and invalid lengths rather than silently returning a surprising result:
import secrets
def random_string(length: int, alphabet: str) -> str:
if length < 0:
raise ValueError('length must be non-negative')
if not alphabet:
raise ValueError('alphabet must not be empty')
return ''.join(secrets.choice(alphabet) for _ in range(length))
if __name__ == '__main__':
print(random_string(24, 'abcdefghijklmnopqrstuvwxyz0123456789'))
This helper returns an empty string for length zero. If your application considers zero invalid, change the check to length <= 0. Repeated characters in the alphabet effectively give those characters more weight, so use a set-like alphabet without duplicates when you want each distinct character to have equal selection probability.
7. Character sets and Unicode considerations
- ASCII letters:
string.ascii_letters - Lowercase ASCII letters:
string.ascii_lowercase - Uppercase ASCII letters:
string.ascii_uppercase - Digits:
string.digits - Punctuation:
string.punctuation
Combine only the classes your output is allowed to contain. Punctuation can require escaping in shells, HTML, URLs, or configuration files, so a URL-safe or alphanumeric alphabet may be easier to handle when the output will cross those boundaries.
You can supply Unicode characters in a custom alphabet, but a Python string’s characters are Unicode code points; a user-perceived symbol may consist of multiple code points. If the requirement is a fixed number of visible grapheme clusters, define and validate that separately. For interoperable tokens, an explicitly chosen ASCII alphabet is usually simpler.
8. Common errors and troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
IndexError: Cannot choose from an empty sequence |
The alphabet is empty. | Validate it before calling choice; provide at least one allowed character. |
| The result is shorter or longer than expected | A token helper’s byte count was mistaken for a character count, or a different length was passed to the loop. | Use repeated secrets.choice for an exact count; use token_urlsafe when byte-based token sizing is suitable. |
| The string uses unexpected characters | The alphabet contains additional classes, or a custom alphabet includes unintended entries. | Print or inspect the alphabet and build it from explicit character classes. |
| The same values appear after each run | A seeded random.Random instance reproduces its sequence. |
Remove the fixed seed for ordinary non-repeatable samples; use secrets for secrets. |
| A password fails a composition rule | Uniform selection from a combined alphabet does not guarantee every class appears. | Use secure candidate-and-retry validation or select required classes first and securely shuffle. |
| Generated password is stored in plain text | Generation and storage were treated as the same problem. | Store passwords with a salted, strong one-way password hash; do not store recoverable passwords. |
| Token characters break a URL or shell command | The chosen alphabet includes reserved or special characters. | Use secrets.token_urlsafe for URL-safe encoded tokens, or restrict an exact-length custom alphabet to safe characters. |
9. Performance, reliability, and cost
These methods use Python’s standard library and require no external package or service. A length-L string requires L selections and joining the selected characters; for normal identifiers, test fixtures, and tokens, this is straightforward. The research sources provide no performance benchmark, so choose based on security and output requirements rather than an assumed speed comparison.
For constrained passwords, rejection sampling may generate more than one candidate before finding one that meets the rules. If constraints become complicated, constructing required classes first and securely shuffling can make the behavior more predictable. For tokens, choose enough random input for your use case; the secrets documentation’s historical note about 32 bytes refers to what was considered sufficient for typical use as of 2015, and explicitly cautions that suitable entropy changes as computers become more capable. Do not treat that dated note as a timeless guarantee.
10. Or skip the browser setup
If your project also needs website screenshots for documentation, previews, or visual checks, ScreenshotNeo is a website screenshot API and MCP server. One GET request returns an image or PDF; it is separate from generating random strings. The full request options are in the ScreenshotNeo documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
ScreenshotNeo accepts cookie or consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; those steps can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Sign up free for 1,000 screenshots a month, with no card.
11. Frequently asked questions
Does Python have a built-in function for a random string?
There is no single standard-library function that creates an arbitrary exact-length string from a custom alphabet. The short pattern is to join repeated calls to choice; use random for non-security data and secrets for secrets.
Is secrets.token_urlsafe(16) a 16-character string?
No. The argument is the number of random bytes. The URL-safe encoded result is longer and its output length is approximate.
Can I use random.choice for a password?
No. Use secrets.choice or another security-reviewed password-generation approach for passwords and tokens.
How do I generate a string with no repeated characters?
That is a different requirement from independent random selection. Use secure sampling without replacement, such as secrets.SystemRandom().sample, and ensure the requested length does not exceed the number of distinct alphabet characters.
Does generating a password securely mean I can store it as text?
No. Password generation and password storage are separate. Store passwords as salted, strong one-way hashes rather than recoverable text.


