OpenCode 实践课:4 分钟用 Python 写出一个命令行密码生成器

项目介绍

今天用 OpenCode 写一个命令行随机密码生成器。输入一条指令,就能按指定长度、字符集生成高强度的随机密码,支持批量生成和密码强度评估。

  • 语言:Python 3.8+
  • 依赖:零第三方库,只用标准库 secretsargparsestring
  • 代码量:约 80 行
  • 用时:≈ 4 分钟

最终效果:

$ python pwdgen.py -l 20 -n 3
Xq7#mKp2@vR9&yLw3!sN
jT5$hF8=cW3^nVb6@zQ1
Gd9%rE2*Px4~mA7#kL0

$ python pwdgen.py -l 16 --no-symbols
密码:  aB3kQ9xR2mN5vF7w
熵值:  95.2 bits

准备工作

  • Python 3.8 及以上
  • 安装 OpenCode(opencode.ai 下载)
  • 在终端进入项目目录

实践过程

第 1 步:让 OpenCode 创建基础密码生成器

直接告诉 OpenCode 要做什么:

> 我对 OpenCode 说
> "用 Python 写一个命令行密码生成器,使用 argparse 解析参数,接受 --length 和 --count 两个选项,用 secrets 模块生成安全随机密码。保存到 pwdgen.py。"

OpenCode 会自动查找代码库中的 Python 文件了解项目风格,然后一次性生成完整代码:

import argparse
import secrets
import string

def generate_password(length=16):
    chars = string.ascii_letters + string.digits + string.punctuation
    return ''.join(secrets.choice(chars) for _ in range(length))

def main():
    parser = argparse.ArgumentParser(description="安全密码生成器")
    parser.add_argument("-l", "--length", type=int, default=16)
    parser.add_argument("-n", "--count", type=int, default=1)
    args = parser.parse_args()

    for _ in range(args.count):
        print(generate_password(args.length))

if __name__ == "__main__":
    main()

关键要点:OpenCode 自动选择 secrets.choice 而非 random.choice——因为 secrets 模块是密码学安全的,适合生成密码。这说明它理解场景语义。

第 2 步:增加字符集控制选项

基础版本生成后,我希望增加更细粒度的控制——可以排除大写字母、数字或符号:

> 我对 OpenCode 说
> "给 generate_password 增加三个布尔参数:upper、digits、symbols,默认全为 True。添加对应的命令行选项 --no-upper、--no-digits、--no-symbols。"

OpenCode 理解了这个需求,准确定位到 generate_password 函数和 argparse 部分,同时做了修改:

def generate_password(length=16, upper=True, digits=True, symbols=True):
    chars = string.ascii_lowercase
    if upper:
        chars += string.ascii_uppercase
    if digits:
        chars += string.digits
    if symbols:
        chars += "!@#$%^&*()-_=+[]{}|;:,.<>?"
    return ''.join(secrets.choice(chars) for _ in range(length))

为什么把 string.punctuation 换成自定义符号集?因为 string.punctuation 包含反斜杠和引号,在 Shell 中容易引起转义问题。OpenCode 在这个细节上表现出了工程意识。

第 3 步:增加歧义字符过滤和强度评估

继续迭代,加上"排除歧义字符"和"密码强度显示":

> 我对 OpenCode 说
> "加一个 --no-ambiguous 选项,排除容易混淆的字符(0/O、1/l/I 等)。再增加密码熵值计算,每个密码后面显示熵值(bits),格式改成 '密码: xxx\n熵值: xx.x bits'。"

OpenCode 在已有代码上直接增补,不会打乱原有结构:

def entropy(password, chars):
    import math
    return len(password) * math.log2(len(set(chars)))

# 在 generate_password 中
if no_ambiguous:
    ambiguous = "il1Lo0O"
    chars = "".join(c for c in chars if c not in ambiguous)

关键要点:我并没有告诉 OpenCode 具体从哪些字符里排除,也没有说熵值公式怎么写——它根据"排除混淆字符""熵值计算"这些自然语言描述,自己推导出了实现方案。

第 4 步:收尾——入口保护和最小长度校验

最后再补一个安全下限和程序入口:

> 我对 OpenCode 说
> "最短密码长度限制为 4,加一个 minimum check;补充 __main__ 入口,使用 argparse 解析参数并调用函数。"

OpenCode 把前面分散的逻辑整合成了一个完整的、可以独立运行的 CLI 程序。全程我没写一行代码,只是用自然语言描述需求。

完整代码

#!/usr/bin/env python3
"""命令行随机密码生成器 —— 100% 标准库,零依赖。"""

import argparse
import math
import secrets
import string
import sys


def generate_password(length=16, upper=True, digits=True,
                      symbols=True, no_ambiguous=False):
    """生成一个安全随机密码。"""
    chars = string.ascii_lowercase
    if upper:
        chars += string.ascii_uppercase
    if digits:
        chars += string.digits
    if symbols:
        chars += "!@#$%^&*()-_=+[]{}|;:,.<>?"

    if no_ambiguous:
        ambiguous = "il1Lo0O"
        chars = "".join(c for c in chars if c not in ambiguous)

    if not chars:
        raise ValueError("没有可用的字符集")

    return "".join(secrets.choice(chars) for _ in range(length))


def calc_entropy(password, chars):
    """计算密码熵值(bits)。"""
    unique = len(set(chars))
    return len(password) * math.log2(unique) if unique else 0


def main():
    parser = argparse.ArgumentParser(
        description="安全随机密码生成器",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="示例: python pwdgen.py -l 20 -n 5 --no-symbols",
    )
    parser.add_argument("-l", "--length", type=int, default=16,
                        help="密码长度(默认 16)")
    parser.add_argument("-n", "--count", type=int, default=1,
                        help="生成数量(默认 1)")
    parser.add_argument("--no-upper", action="store_true",
                        help="不含大写字母")
    parser.add_argument("--no-digits", action="store_true",
                        help="不含数字")
    parser.add_argument("--no-symbols", action="store_true",
                        help="不含特殊符号")
    parser.add_argument("--no-ambiguous", action="store_true",
                        help="排除歧义字符 (il1Lo0O)")

    args = parser.parse_args()

    if args.length < 4:
        print("错误:密码长度至少为 4", file=sys.stderr)
        sys.exit(1)

    chars = string.ascii_lowercase
    if not args.no_upper:
        chars += string.ascii_uppercase
    if not args.no_digits:
        chars += string.digits
    if not args.no_symbols:
        chars += "!@#$%^&*()-_=+[]{}|;:,.<>?"
    if args.no_ambiguous:
        ambiguous = "il1Lo0O"
        chars = "".join(c for c in chars if c not in ambiguous)

    for _ in range(args.count):
        pwd = generate_password(
            length=args.length,
            upper=not args.no_upper,
            digits=not args.no_digits,
            symbols=not args.no_symbols,
            no_ambiguous=args.no_ambiguous,
        )
        ent = calc_entropy(pwd, chars)
        print(f"密码:  {pwd}")
        print(f"熵值:  {ent:.1f} bits\n")


if __name__ == "__main__":
    main()

使用示例

# 默认生成 16 位密码,1 条
$ python pwdgen.py

# 生成 5 条 20 位密码
$ python pwdgen.py -l 20 -n 5

# 纯字母数字,排除歧义字符
$ python pwdgen.py -l 12 --no-symbols --no-ambiguous

小结

整个项目从零到完整可运行,花了大约 4 分钟。这 4 分钟里我没写一行代码,只是用自然语言告诉 OpenCode:

"帮我写一个密码生成器"

"加几个参数控制字符集"

"排除歧义字符,算一下强度"

"加长度校验和入口"

OpenCode 负责了所有的代码生成、语法细节、库选择和边界处理。我只需要关注"我想要什么",不用操心"怎么实现"。

相比传统写法——查文档、写骨架、调 bug、补边界——效率提升了至少 5 倍。更重要的是,这种"对话式编程"让你可以保持心流,想法→表达→出代码→迭代,整个过程像在和白板搭档结对编程。

如果你还没试过 OpenCode,打开终端,试着对它说出你的第一个需求。你会发现:写代码这件事,正在被重新定义。