密码生成应优先使用secrets模块而非random,字符集至少为string.ascii_letters+string.digits,可选添加安全符号,避免易混淆字符和强制去重。

string.ascii_letters + string.digits 是密码字符集的底线
别用 string.printable,它包含空格、换行、制表符甚至不可见控制字符,直接导致密码生成失败或粘贴时出错。真实可用的最小安全字符集是大小写字母加数字:string.ascii_letters + string.digits。如果业务允许,再叠加 string.punctuation 里的部分符号(比如排除 '、"、\、 这类易引发解析问题的字符)。
random.choices() 比 random.choice() 循环调用快且线程安全
用 random.choice() 写 for 循环拼接密码,不仅写法啰嗦,还可能在多线程环境下因共享 random.Random 实例状态而出问题。直接上 random.choices() —— 它一次返回指定长度的列表,底层用 C 实现,速度更快,且默认使用线程本地的随机实例。
示例:
import string, random chars = string.ascii_letters + string.digits + "!@#$%&*" password = ''.join(random.choices(chars, k=16))
secrets 模块才是生产环境唯一推荐方案
random 模块的输出可被预测,不适用于密码、token、密钥等安全敏感场景。secrets 才是 Python 3.6+ 专为密码学安全随机数设计的标准库模块。它底层调用操作系统级熵源(如 Linux 的 /dev/urandom),无法被种子复现。
关键点:
-
secrets.choice()替代random.choice(),用于单字符选取 -
secrets.SystemRandom()可替代random的所有方法,但多数情况直接用secrets.choice()更清晰 - 不要对
secrets结果再做random.shuffle()或其他非确定性加工——这反而可能削弱熵值
正确写法:
import secrets, string chars = string.ascii_letters + string.digits + "!@#$%&*" password = ''.join(secrets.choice(chars) for _ in range(16))
避免常见陷阱:长度、重复、字符分布
生成 16 位密码不等于强度高——如果字符集只有小写字母,那总组合数仅是 26¹⁶;而加入大小写+数字+5个符号后,变成 67¹⁶,差距超 10²⁰ 倍。所以优先扩大字符集,再保长度。
另外,secrets.choice() 允许重复,这是正常且必要的(否则叫“随机排列”而非“随机密码”);强行去重会显著降低熵值,还可能因字符集小于要求长度而抛 ValueError。
真正要防的是肉眼难辨的字符:比如 0 和 O、1 和 l。若面向终端用户,建议显式剔除它们:
chars = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789!@#$%&*"
这个细节常被跳过,但直接影响用户抄错率和客服工单量。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











