AI编程(十四):密码生成器 — 随机数和字符串的妙用

作者:

用随机数+字符串操作,做一个帮你生成强密码的小工具

一、你是不是也有这个问题

注册一个新网站,它要求你设置密码:

  • 必须8位以上
  • 必须包含大写字母
  • 必须包含数字
  • 不能和以前的密码重复

你想了半天,输入”zhangsan1990″——系统提示:太简单。

改成”Zhangsan1990!”——好像行了,但这个密码你已经用了三个网站了。

一个好密码应该是完全随机的,比如 Kp7#mQx2&Rn9 这种。但人脑不擅长制造随机——你随手敲的”乱码”,往往还是有规律的(键盘上相邻的键、熟悉的拼音、生日年份)。

那谁擅长制造随机?程序

今天我们做一个密码生成器:程序帮你生成真正随机的强密码。用到的全是学过的东西:随机数、字符串拼接、循环、列表、函数

二、先搞懂密码是怎么”造”出来的

一个强密码,本质上就是从一大堆字符里随机挑几个,拼在一起

这个”一大堆字符”包括四类:

  • 小写字母:abcdefghijklmnopqrstuvwxyz
  • 大写字母:ABCDEFGHIJKLMNOPQRSTUVWXYZ
  • 数字:0123456789
  • 特殊符号:!@#$%^&*

生成一个12位密码,就是从这堆字符里随机抽12次,每次抽出一个字符,连起来。

就像抽奖:把所有字符写成小球扔进箱子,闭着眼睛摸12次,每次摸到什么就记下来。

三、先跟AI聊

你的提示词:

用Python写一个密码生成器。从大小写字母、数字、特殊符号中随机选取字符,生成一个12位的随机密码并打印出来。加上详细的中文注释。

AI会给你一段代码,大概长这样:

import random
import string

# 所有可用的字符:大小写字母+数字+特殊符号
all_chars = string.ascii_letters + string.digits + string.punctuation

# 生成12位密码
password = ""
for i in range(12):
    # 从所有字符中随机选一个
    char = random.choice(all_chars)
    # 拼接到密码后面
    password = password + char

print(f"生成的密码是:{password}")

四、逐行理解

第1-2行:两个工具箱

import random
import string

第13篇已经用过random了(生成随机数)。今天多认识一个工具箱:string

string是Python自带的模块,里面存着一些常用的字符串。你可以把import理解成”打开工具箱盖子”。

第4行:攒一池子字符

all_chars = string.ascii_letters + string.digits + string.punctuation

这里用了字符串拼接(第四篇学的,用+号把字符串连起来):

内容 实际是什么

|——|———–|

string.ascii_letters 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'(全部大小写字母)
string.digits '0123456789'
string.punctuation '!"#$%&'()*+,-./:;?@[\]^_{ }~’`(各种符号)

三个字符串用+连起来,存进变量all_chars。现在这个变量里有90多个字符,就是我们的”抽奖箱”。

为什么用现成的变量而不自己写 'abc...XYZ' 不是不能写,而是容易写漏写错。string模块已经帮你准备好了,程序员的懒惰美德:能用现成的就不自己造。

第6-7行:空字符串和循环

password = ""
for i in range(12):

password = ""——先准备一个空字符串,就像一张白纸,等下往上面”写”密码。

for i in range(12)——循环12次。还记得第八篇的for循环吗?range(12)会生成0到11共12个数字,循环体就执行12遍。

(这里的i其实没用上,纯粹是让循环跑12次。Python不介意。)

第9行:随机抽一个字符

char = random.choice(all_chars)

random.choice()的意思是:从一串东西里随机挑一个。它是random工具箱里的另一个工具(第13篇用的是random.randint(),生成随机整数;这个是随机挑元素)。

每次循环,从90多个字符里随机挑一个,存进char

第11行:拼接

password = password + char

把刚抽到的字符接到密码末尾。第一次循环后,password变成1个字符;第二次变成2个……12次循环后,就是一个12位的随机密码。

这个写法值得看仔细:password = password + char的意思是”用password加上char,组成新的字符串,再存回password”。就像往一串珠子上不断加新珠子。

五、运行试试

保存为password.py,运行:

python password.py

我运行了三次,得到:

生成的密码是:k3!Qx&m9Rn#p
生成的密码是:7Tz$wL2@jH5c
生成的密码是:Pq8#nX4&bK1m

每次都不一样,而且完全没有规律——这正是强密码该有的样子。复制一个拿去注册,比你自己想的”姓名+生日”安全得多。

六、第一个改进:可选密码长度

12位是写死的。但有时候网站要求8位,有时候你想生成20位的超长密码。

改成让用户输入长度:

import random
import string

all_chars = string.ascii_letters + string.digits + string.punctuation

# 让用户输入密码长度
length_input = input("你想生成几位的密码?(直接回车默认12位):")

# 如果用户直接回车,用默认值12
if length_input == "":
    length = 12
else:
    length = int(length_input)

password = ""
for i in range(length):
    char = random.choice(all_chars)
    password = password + char

print(f"生成的{length}位密码是:{password}")

改动点:

  • input()问用户要几位
  • 如果用户直接按回车(输入空字符串),用默认值12位
  • 循环次数从写死的12改成变量length

注意一个细节input()返回的是字符串,range()需要整数,所以用int()转换(第13篇讲过)。

这里还有个隐患:如果用户输入”abc”,int("abc")会崩溃。修复方法你已经会了——try...except。这是第13篇做过的练习,留给你自己加(提示词可以这么问AI:”给密码生成器加输入验证,用户输入非数字时用默认长度12″)。

七、第二个改进:可选包含哪些字符

有些网站的密码不允许特殊符号。有些公司规定密码必须全是数字(比如PIN码)。我们让用户自己选:

import random
import string

print("=== 密码生成器 ===")
print("请选择密码包含的字符类型(可多选,用逗号分隔):")
print("1. 小写字母")
print("2. 大写字母")
print("3. 数字")
print("4. 特殊符号")

choice = input("你的选择(如 1,2,3):")

# 先准备一个空的"字符池"
all_chars = ""

# 根据用户的选择,往池子里加对应的字符
if "1" in choice:
    all_chars = all_chars + string.ascii_lowercase
if "2" in choice:
    all_chars = all_chars + string.ascii_uppercase
if "3" in choice:
    all_chars = all_chars + string.digits
if "4" in choice:
    all_chars = all_chars + string.punctuation

# 如果用户啥都没选,就全都要
if all_chars == "":
    all_chars = string.ascii_letters + string.digits + string.punctuation
    print("(没选?那我就全用上)")

length = int(input("密码长度(默认12):") or 12)

password = ""
for i in range(length):
    char = random.choice(all_chars)
    password = password + char

print(f"你的密码是:{password}")

这里有几个值得拆开看的点:

"1" in choice —— 字符串里的in操作

用户输入的是字符串,比如"1,3"if "1" in choice:的意思是:这个字符串里有没有包含字符”1″。

in操作你学过:第13篇用if guess in guess_history:检查列表里有没有某数字。它对字符串同样好用——检查”大字符串里包不包含某个小字符串”。

所以用户输入1,3133,1都能被识别。不用in的话,你得处理各种输入格式,麻烦多了。

逐项累加字符池

all_chars = ""
if "1" in choice:
    all_chars = all_chars + string.ascii_lowercase
...

一开始是空池子,每满足一个条件就往里加一类字符。四个独立的if(不是if/elif),因为用户可以同时选多项。

input(...) or 12 —— 偷懒的默认值技巧

length = int(input("密码长度(默认12):") or 12)

这行有点trick(技巧)。拆开看:

  1. input(...) 让用户输入,返回字符串
  2. 如果用户直接回车,返回空字符串""
  3. "" or 12 —— Python会”挑选”or两边第一个”有内容”的值。空字符串被视为”没有内容”,所以结果是12
  4. int(...) 把结果转成整数

这样一行就实现了”有输入用输入,没输入用默认”。你看不懂没关系,问AI:”解释一下 x = input() or 12 这种写法的原理”。

运行效果

=== 密码生成器 ===
请选择密码包含的字符类型(可多选,用逗号分隔):
1. 小写字母
2. 大写字母
3. 数字
4. 特殊符号
你的选择(如 1,2,3):1,2,3
密码长度(默认12):16
你的密码是:kT3mQxRn7bWpL2jH

选1,2,3(不要特殊符号),生成的密码里就真的一个符号都没有。需要纯数字PIN码?输入3,长度6,得到847291

八、第三个改进:用函数重构 + 一次生成多个

现在我们把生成密码的逻辑装进函数(第九篇学的),顺便加一个”一次生成5个密码,你挑一个喜欢的”功能:

import random
import string


def make_password(length=12, use_lower=True, use_upper=True,
                  use_digit=True, use_symbol=True):
    """生成一个随机密码

    参数:
        length: 密码长度
        use_lower: 是否包含小写字母
        use_upper: 是否包含大写字母
        use_digit: 是否包含数字
        use_symbol: 是否包含特殊符号
    """
    # 根据参数组装字符池
    all_chars = ""
    if use_lower:
        all_chars = all_chars + string.ascii_lowercase
    if use_upper:
        all_chars = all_chars + string.ascii_uppercase
    if use_digit:
        all_chars = all_chars + string.digits
    if use_symbol:
        all_chars = all_chars + string.punctuation

    # 生成密码
    password = ""
    for i in range(length):
        char = random.choice(all_chars)
        password = password + char

    # 函数的产出:把生成的密码交出去
    return password


# === 主程序 ===
print("=== 密码生成器 ===")

choice = input("包含哪些?(1小写 2大写 3数字 4符号,如1,2,3):")
length_input = input("密码长度(默认12):")

length = int(length_input) if length_input else 12

# 一次生成5个密码
print("n为你生成了5个密码:")
for i in range(5):
    pwd = make_password(
        length=length,
        use_lower="1" in choice,
        use_upper="2" in choice,
        use_digit="3" in choice,
        use_symbol="4" in choice,
    )
    print(f"  {i + 1}. {pwd}")

函数带来了什么

以前的代码是”一整条流水线”,从问用户到生成密码到打印,全混在一起。现在make_password()只负责一件事:给我参数,还你密码。

好处立刻体现出来:

1. 生成5个密码只要一个循环

for i in range(5):
    pwd = make_password(length=length, ...)
    print(f"  {i + 1}. {pwd}")

函数可以被反复调用。要10个密码?把5改成10就行。以前的写法你得把生成代码复制粘贴5遍。

2. 逻辑可以复用

以后你做任何需要随机字符串的东西(生成验证码、生成用户名、生成测试数据),把make_password()搬过去就能用。函数就是”打包好的手艺”。

3. 默认参数值

def make_password(length=12, use_lower=True, ...)

参数后面的=默认值:调用时不写这个参数,就用默认值。所以make_password()(什么都不传)也能工作,直接给你一个12位全字符密码。

if "1" in choice 搬到了调用处

注意这行:

use_lower="1" in choice,

"1" in choice的结果是TrueFalse(布尔值),正好匹配函数参数。用户输入的解析(”1,2,3″是啥意思)和密码生成的逻辑(怎么挑字符)分开了。这是写代码的一个重要习惯:每块代码只管自己的事。

运行效果

=== 密码生成器 ===
包含哪些?(1小写 2大写 3数字 4符号,如1,2,3):1,2,3
密码长度(默认12):10

为你生成了5个密码:
  1. kT3mQxRn7b
  2. Wp2LjH8sKx
  3. Rn9bQm4TzW
  4. jH5cPq7nX2
  5. bK1mL2wT9p

挑一个顺眼的用。如果哪个”长得像脏话”或者”看起来不吉利”,换一个就是——反正生成不要钱。

九、回顾一下用到了什么

知识点 在哪里用的

|——–|———–|

import模块 random、string两个工具箱
变量 all_chars, password, length
字符串拼接 all_chars + string.digitspassword + char
空字符串 password = "" 从白纸开始积累
循环 for i in range(12) 抽12次
条件判断 根据选择决定加哪类字符
in操作 "1" in choice 检查输入包含什么
函数 make_password 打包生成逻辑
默认参数 length=12 不传就用默认
return 函数把结果交出去
f-string 格式化输出密码

11个知识点,没有一个是新的。 string模块严格说算”新见面”,但它不是新知识——它只是import这个老知识的一次新应用。

十、今日小练习

试着自己加一个功能(可以问AI帮忙):

功能:给密码”评分”

生成密码后,程序顺便告诉你这个密码的强度:

  • 包含4类字符 → “很强 💪”
  • 包含3类字符 → “较强 👍”
  • 包含2类字符 → “一般 😐”
  • 只包含1类字符 → “太弱了 ⚠️”

提示:你需要统计all_chars里被加进了几类字符。想想怎么记录”加了几类”?一个计数器变量就够了(每满足一个if就+1)。

先自己想思路,再问AI,然后对比一下谁的方案更简洁。


下一篇:单词统计器 — 读取一篇文章,用字典统计每个词出现了多少次,找出全文最重要的10个词。这是所有”文本分析”工具的雏形。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注