PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchUse Python’s secrets module—not random—to generate passwords for real credentials. The complete program below accepts a length, lets you enable or disable character categories, guarantees every enabled category appears, and shuffles the result with an operating-system-backed secure random source. It uses only Python’s standard library.
The example defaults to 20 characters. That is a practical starting point, not a universal guarantee: choose a length that fits the service, threat model and whether the password must be typed. NIST consumer guidance recommends passwords of at least 15 characters when a password is required, and recommends unique passwords, password managers, multifactor authentication and passkeys (NIST guidance).
What a secure password generator must do
A random password generator selects characters (or words) using a random source. Security depends on whether that source is unpredictable. Python documents secrets as suitable for passwords, authentication secrets and security tokens, and recommends it over random for security-sensitive work (Python secrets documentation).
The script in this guide:
- Uses
secrets.choice()for every character. - Supports lowercase letters, uppercase letters, digits and symbols independently.
- Rejects an empty character set and impossible lengths.
- Places at least one character from each enabled category.
- Securely shuffles the completed list so category positions are not predictable.
- Prints one result and does not save it automatically.
Python’s string module supplies the standard ASCII collections used here (Python string documentation).
Recommended Free Tools
#1 Best Overall
Minimal version for understanding
This short program is useful for seeing the core operation:
import secrets
import string
alphabet = string.ascii_letters + string.digits + string.punctuation
password = "".join(secrets.choice(alphabet) for _ in range(20))
print(password)
Every character is selected securely, but this version does not guarantee a digit, uppercase letter or symbol. A result could contain only letters by chance. Use the configurable version below when a service has composition rules.
Complete configurable password generator
Save this as password_generator.py:
#!/usr/bin/env python3
import argparse
import secrets
import string
CHARACTER_SETS = {
"lowercase": string.ascii_lowercase,
"uppercase": string.ascii_uppercase,
"digits": string.digits,
"symbols": string.punctuation,
}
def generate_password(
length=20,
use_lowercase=True,
use_uppercase=True,
use_digits=True,
use_symbols=True,
):
"""Generate a cryptographically secure random password."""
selected_sets = []
if use_lowercase:
selected_sets.append(CHARACTER_SETS["lowercase"])
if use_uppercase:
selected_sets.append(CHARACTER_SETS["uppercase"])
if use_digits:
selected_sets.append(CHARACTER_SETS["digits"])
if use_symbols:
selected_sets.append(CHARACTER_SETS["symbols"])
if not selected_sets:
raise ValueError("At least one character category must be enabled.")
if length < len(selected_sets):
raise ValueError(
f"Length must be at least {len(selected_sets)} "
"to include every selected character category."
)
if length > 4096:
raise ValueError("Length must not exceed 4096 characters.")
alphabet = "".join(selected_sets)
# Guarantee one character from each enabled category.
password_characters = [
secrets.choice(character_set)
for character_set in selected_sets
]
# Fill the remaining positions from the combined alphabet.
password_characters.extend(
secrets.choice(alphabet)
for _ in range(length - len(password_characters))
)
# Hide the fixed category positions with a secure shuffle.
secrets.SystemRandom().shuffle(password_characters)
return "".join(password_characters)
def main():
parser = argparse.ArgumentParser(
description="Generate a cryptographically secure random password."
)
parser.add_argument(
"-l", "--length", type=int, default=20,
help="Password length; default: 20",
)
parser.add_argument(
"--no-lowercase", action="store_true",
help="Exclude lowercase letters.",
)
parser.add_argument(
"--no-uppercase", action="store_true",
help="Exclude uppercase letters.",
)
parser.add_argument(
"--no-digits", action="store_true",
help="Exclude digits.",
)
parser.add_argument(
"--no-symbols", action="store_true",
help="Exclude punctuation symbols.",
)
args = parser.parse_args()
try:
password = generate_password(
length=args.length,
use_lowercase=not args.no_lowercase,
use_uppercase=not args.no_uppercase,
use_digits=not args.no_digits,
use_symbols=not args.no_symbols,
)
except ValueError as error:
parser.error(str(error))
print(password)
if __name__ == "__main__":
main()
Run it from a terminal
Check your Python version
The secrets module was introduced in Python 3.6. Check the interpreter you will use:
python --version
If that command is unavailable or points to Python 2, try:
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchespython3 --version
No third-party package is required.
Generate the default password
python password_generator.py
On systems using python3:
python3 password_generator.py
The output is one new 20-character password. It will differ on every run.
Choose a length
python password_generator.py --length 32
python password_generator.py -l 24
Disable categories
For a letters-only result:
python password_generator.py --length 24 --no-digits --no-symbols
At least one category must remain enabled. With all four enabled, a length below four cannot satisfy the requirements:
Rank #2
python password_generator.py --length 3
argparse reports an error and exits instead of returning an invalid password. Disabling every category produces the same kind of clear error.
Why secrets is safer than random
random is designed for simulations and ordinary pseudorandom behavior, not for protecting secrets. Its output can be predictable in security-sensitive situations. The Python documentation explicitly directs developers to secrets for passwords (Python random documentation; Python secrets documentation).
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Do not use this for credentials:
import random
import string
password = "".join(
random.choice(string.ascii_letters + string.digits)
for _ in range(20)
)
secrets.choice() selects from a non-empty sequence using a security-oriented source. SystemRandom().shuffle() uses the strongest randomness source available from the operating system, rather than a predictable fixed-position shuffle.
How category guarantees and shuffling work
- The function collects each enabled character set.
- It chooses one character independently from every selected set.
- It fills the remaining positions from the combined alphabet.
- It shuffles the complete list securely.
A one-line generator has unbiased selections but can omit a category by chance. Fixed placement is also undesirable: if the first four positions are always lowercase, uppercase, digit and symbol, an attacker learns a pattern. Selecting first and shuffling solves both practical problems.
Symbols, punctuation and ambiguous characters
string.punctuation contains these ASCII characters:
!"#$%&'()*+,-./:;<=>?@[]^_`{|}~
Websites frequently allow only some punctuation or reject particular characters. Treat symbol support as configurable, and use a service-specific allow-list when an application documents one. NIST prioritizes length and does not recommend universally requiring special characters and numbers (NIST guidance).
For passwords that must be read aloud or typed, you can remove visually similar characters before selecting:
AMBIGUOUS = set("0Oo1lI")
def remove_ambiguous(characters):
return "".join(c for c in characters if c not in AMBIGUOUS)
Apply this to the pools before generation. It slightly reduces the alphabet and is usually unnecessary when a password manager can copy the result exactly. Keep the core script ASCII unless you deliberately handle Unicode normalization and a service’s encoding rules.
Length, passphrases and entropy
Choosing a length
The sample uses 20 characters and accepts longer values such as 24 or 32. There is no length that guarantees safety against phishing, malware, account recovery attacks or a breached service. Service maximums, whether the password is manually typed and the attacker model all matter.
Passphrases
A passphrase selects several independently chosen words from a vetted, sufficiently large word list. It can be easier to type and remember, but a tiny hand-written list makes outcomes predictable. NIST presents passphrases as a way to create longer, memorable passwords (NIST guidance). Use secrets.choice for every word and account for sites that reject spaces or impose short limits.
What entropy means
For an ideal uniform generator, a length L chosen from an alphabet of size N has approximately L × log2(N) bits of entropy. That model assumes the source is unpredictable, the password is unique and no output is exposed. It is not a promise of a particular crack time.
Generation is not storage or hashing
Printing is convenient for a local exercise, but terminal scrollback, CI logs, recordings and clipboard managers can retain the secret. Do not automatically write passwords to a file:
with open("passwords.txt", "a") as file:
file.write(password + "n")
This creates a plaintext credential store that may leak through backups, synchronization, permissions or source control. Avoid source code, shared spreadsheets, shell history and unprotected logs. If you build an account system, never store recoverable passwords. Store a salted password hash using a password-storage algorithm; OWASP discusses Argon2id and scrypt and the controls around them (OWASP Password Storage Cheat Sheet).
Generation creates a secret. Hashing protects a user-supplied password for later verification. A reset token is a separate, temporary secret requiring expiration and single-use controls. A strength estimator only evaluates guessability; it does not repair a weak password.
Tests that check behavior
These dependency-free checks can be placed below the function or in a separate test file:
def test_length():
password = generate_password(length=32)
assert len(password) == 32
def test_required_categories():
password = generate_password(length=20)
assert any(c.islower() for c in password)
assert any(c.isupper() for c in password)
assert any(c.isdigit() for c in password)
assert any(c in string.punctuation for c in password)
def test_letters_only():
password = generate_password(
length=20,
use_lowercase=True,
use_uppercase=True,
use_digits=False,
use_symbols=False,
)
assert password.isalpha()
def test_invalid_length():
try:
generate_password(length=3)
except ValueError:
pass
else:
raise AssertionError("Expected ValueError")
def test_no_categories():
try:
generate_password(
length=20,
use_lowercase=False,
use_uppercase=False,
use_digits=False,
use_symbols=False,
)
except ValueError:
pass
else:
raise AssertionError("Expected ValueError")
Also test that disabled categories never appear, length one works when only one category is enabled, invalid command-line arguments exit nonzero, and any application-specific maximum is enforced. Do not expect a particular password or demand a perfectly uniform distribution from a small sample.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Common failures and fixes
“python: command not found”
Install a current Python 3 release, or use the platform command such as python3. Confirm the version in the same terminal where you run the script.
“Length must be at least …”
You enabled more categories than the requested length. Increase the length or disable a category.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Best Value
All categories disabled
Enable at least one of lowercase, uppercase, digits or symbols. An empty alphabet cannot be sampled.
A website rejects the output
Check its documented allowed characters and maximum length. Disable symbols or replace string.punctuation with an explicit allow-list. Do not “fix” a generated password with predictable substitutions such as capitalize(), appending ! or replacing letters with @.
The password appeared in logs
Assume it is exposed, revoke or change it, and remove it from logs and shell history where possible. For automation, use a protected secret store and controlled output instead of printing.
When a password manager is the better tool
This script is excellent for learning Python, controlled local testing and integrations where you understand the exposure. For everyday accounts, a password manager is generally more practical because it generates, stores and autofills unique credentials, helps prevent reuse and supports multiple devices. Bitwarden documents configurable password and passphrase generation (Bitwarden generator documentation), 1Password provides a public generator and integrated generation (1Password password generator), and Proton Pass offers a free tier with a generator and multi-device clients (Proton Pass pricing; downloads). These services do not eliminate phishing or malware risks; use multifactor authentication or passkeys where available.
Free tools Windows power users keep installed
One-click scans. No signup required.
Or skip the browser setup
If your project needs website screenshots rather than locally rendered password output, ScreenshotNeo provides a one-call screenshot API and an MCP server for AI agents. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets; failed loads, bot checks, blank pages, timeouts and cache hits are not billed, with the result identified by X-Page-Verdict and X-Billed headers. Claude, Cursor and other MCP clients can use take_screenshot, get_page_info and capture_pdf.
cURL:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python:
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)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
See the ScreenshotNeo API documentation for the 63 options, including full-page and element capture, device presets, custom CSS and JavaScript, waits, blocking, headers, cookies, geolocation, PDFs, caching, signed links, asynchronous jobs and bulk capture. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
Frequently Asked Questions
Can I use this generator inside another Python program?
Yes. Import the file and call generate_password(length=32), passing category flags as needed. Keep the returned value in memory and control where it is sent.
Does a secure generator make an account impossible to hack?
No. It improves unpredictability, but phishing, malware, password reuse, recovery weaknesses and service breaches remain separate risks.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Why does the script cap length at 4096?
The cap is an application safeguard against accidental or hostile requests that allocate excessive memory or flood logs. It is not a universal password standard.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

