每次注册新账号,相信很多小伙伴们会在“123456”、“生日+姓名”和“记不住的乱码”之间反复妥协。今天,我们来用 Python 标准库实现一个真正具备密码学安全性的密码生成器。代码大约 80 行,零第三方依赖,界面简洁,开箱即用,效果如下。

random 生成密码?Python 的 random 模块底层使用 Mersenne Twister 算法。它是一种高质量的伪随机数生成器,适用于模拟、游戏或抽样,但不是加密安全的。它的内部状态在足够多的输出后是可预测的,攻击者一旦捕获部分输出,就有可能推演出后续生成的“随机”密码。
Python 3.6 引入了 secrets 模块,它直接调用操作系统底层的 CSPRNG(加密安全伪随机数生成器,如 Linux 的 /dev/urandom、Windows 的 CryptGenRandom)。专为密钥、Token、密码等安全场景设计,不可预测、不可重现。因此生成密码,请始终使用 secrets。
仅依赖 tkinter、string、secrets,无需 pip install。Windows、macOS、Linux 均可直接执行。
通过复选框状态动态拼接 string.ascii_uppercase、string.digits 等常量。避免硬编码符号集,也方便后续扩展(如剔除易混淆字符 O0l1I)。
password = ''.join(secrets.choice(pool) for _ in range(length))使用生成器表达式配合 secrets.choice,在密码学安全的字符池中均匀采样。长度由用户控制,默认 12 位,建议 ≥12。
self.root.clipboard_clear()self.root.clipboard_append(pwd)self.root.update() # 关键:确保部分系统成功写入
tkinter 的剪贴板操作在 macOS 和部分 Linux 桌面环境下是异步的。调用 root.update() 可强制刷新事件循环,避免“复制了但粘贴为空”的偶发问题。按钮提供 1.2 秒视觉反馈,交互更自然。
可直接运行
import tkinter as tkfrom tkinter import messageboximport stringimport secretsclass PasswordGenerator:def __init__(self, root):self.root = rootself.root.title("🔐 强密码生成器")self.root.geometry("420x300")self.root.resizable(False, False)self.length_var = tk.IntVar(value=12)self.upper_var = tk.BooleanVar(value=True)self.lower_var = tk.BooleanVar(value=True)self.digits_var = tk.BooleanVar(value=True)self.symbols_var = tk.BooleanVar(value=False)self.result_var = tk.StringVar()self._setup_ui()def _setup_ui(self):main = tk.Frame(self.root, padx=20, pady=15)main.pack(fill=tk.BOTH, expand=True)tk.Label(main, text="自定义密码生成器", font=("Arial", 14, "bold")).pack(pady=(0, 10))len_frm = tk.Frame(main)len_frm.pack(fill=tk.X, pady=5)tk.Label(len_frm, text="密码长度:").pack(side=tk.LEFT)tk.Spinbox(len_frm, from_=4, to=32, textvariable=self.length_var, width=5, font=("Consolas", 10)).pack(side=tk.LEFT, padx=5)chk_frm = tk.Frame(main)chk_frm.pack(fill=tk.X, pady=5)tk.Checkbutton(chk_frm, text="大写字母 A-Z", variable=self.upper_var).pack(side=tk.LEFT, padx=5)tk.Checkbutton(chk_frm, text="小写字母 a-z", variable=self.lower_var).pack(side=tk.LEFT, padx=5)tk.Checkbutton(chk_frm, text="数字 0-9", variable=self.digits_var).pack(side=tk.LEFT, padx=5)tk.Checkbutton(chk_frm, text="特殊符号 !@#", variable=self.symbols_var).pack(side=tk.LEFT, padx=5)tk.Button(main, text="🔑 生成密码", command=self.generate,bg="#4CAF50", fg="white", font=("Arial", 10, "bold")).pack(fill=tk.X, pady=15)res_frm = tk.Frame(main)res_frm.pack(fill=tk.X)tk.Entry(res_frm, textvariable=self.result_var, state="readonly",font=("Consolas", 12), justify="center").pack(side=tk.LEFT, fill=tk.X, expand=True)self.copy_btn = tk.Button(res_frm, text="📋 复制", command=self.copy_pwd, width=10)self.copy_btn.pack(side=tk.RIGHT, padx=(5, 0))def generate(self):pool = ""if self.upper_var.get(): pool += string.ascii_uppercaseif self.lower_var.get(): pool += string.ascii_lowercaseif self.digits_var.get(): pool += string.digitsif self.symbols_var.get(): pool += string.punctuationif not pool:messagebox.showwarning("提示", "请至少勾选一种字符类型!")returnlength = self.length_var.get()password = ''.join(secrets.choice(pool) for _ in range(length))self.result_var.set(password)self.copy_btn.config(text="📋 复制")def copy_pwd(self):pwd = self.result_var.get()if not pwd:messagebox.showinfo("提示", "请先生成密码")returnself.root.clipboard_clear()self.root.clipboard_append(pwd)self.root.update()self.copy_btn.config(text="✅ 已复制", bg="#2196F3", fg="white")self.root.after(1200, lambda: self.copy_btn.config(text="📋 复制", bg="SystemButtonFace", fg="black"))if __name__ == "__main__":root = tk.Tk()app = PasswordGenerator(root)root.mainloop()