如何实现类Crunch的密码字典生成器?Python代码优化咨询
代码慢的原因分析
- 递归生成器的开销:Python递归调用和生成器嵌套会带来大量函数调用与上下文切换开销,当密码长度
m较大时,递归深度增加,效率会急剧下降。 - 字符串拼接低效:每次执行
l+j都会创建新的字符串对象,大量小字符串的创建与销毁会额外占用内存和CPU资源。 - IO操作瓶颈:直接用
print输出到控制台是极低效的IO操作;即使写入文件,逐行写入的频繁IO调用也会拖慢整体速度。
代码优化方案
1. 用itertools.product替代递归生成器
itertools.product是Python标准库中C实现的工具,专门用于生成笛卡尔积,效率远高于纯Python递归。它可以直接生成所有字符组合,彻底避免递归带来的开销。
优化后的核心逻辑:
import itertools def brute(m, pattern=None): letters = 'abcdefghijklmnopqrstuvwxyz' spec = '#@&$%*()+' upper = letters.upper() number = '1234567890' info = {'@': spec, '^': upper, '%': letters, '*': number} # 处理模式,生成每个位置对应的字符集 if pattern: # 若pattern长度不足m,用默认小写字母补全 chars = [info.get(p, letters) for p in list(pattern.ljust(m, letters))[:m]] else: chars = [letters] * m # 生成所有组合并返回 for combo in itertools.product(*chars): yield ''.join(combo)
2. 优化IO操作
避免逐行print或逐行写入文件,改为批量处理后写入,减少IO调用次数:
# 示例:批量写入文件 with open('passwords.txt', 'w') as f: count = 0 for pwd in brute(4, '@%^*'): f.write(pwd + '\n') count += 1 # 每生成10000个密码刷新一次缓冲区,避免内存占用过高 if count % 10000 == 0: f.flush()
3. 减少不必要的对象创建
提前处理好字符集列表,避免循环中重复查找或创建对象;用str.join代替字符串拼接——join会预先计算所需内存,一次性创建字符串,效率远高于多次拼接。
实现类似Crunch的完整工具
Crunch的核心功能包括指定密码长度范围、自定义字符集、模式匹配、输出到文件等。基于上述优化,可扩展出完整工具:
import itertools import argparse def generate_passwords(min_len, max_len, pattern=None, charset=None): # 默认字符集 default_charsets = { 'lower': 'abcdefghijklmnopqrstuvwxyz', 'upper': 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'digit': '0123456789', 'spec': '#@&$%*()+' } # 覆盖默认字符集(如果用户指定) if charset: for item in charset: key, val = item.split('=') if key in default_charsets: default_charsets[key] = val # 模式映射规则 pattern_map = { '@': default_charsets['spec'], '^': default_charsets['upper'], '%': default_charsets['lower'], '*': default_charsets['digit'] } # 遍历所有指定长度 for length in range(min_len, max_len + 1): if pattern: # 补全模式至指定长度,超出部分截断 pattern_padded = pattern.ljust(length, '%')[:length] chars = [pattern_map.get(c, c) for c in pattern_padded] else: # 默认使用所有字符的组合 chars = [''.join(default_charsets.values())] * length # 生成所有密码组合 for combo in itertools.product(*chars): yield ''.join(combo) def main(): parser = argparse.ArgumentParser(description='类似Crunch的密码字典生成工具') parser.add_argument('min_len', type=int, help='密码最小长度') parser.add_argument('max_len', type=int, help='密码最大长度') parser.add_argument('-p', '--pattern', help='密码模式:@=特殊字符, ^=大写字母, %=小写字母, *=数字') parser.add_argument('-c', '--charset', nargs='+', help='自定义字符集,格式如 lower=abc upper=ABC') parser.add_argument('-o', '--output', help='输出文件路径') args = parser.parse_args() # 解析自定义字符集参数 custom_charset = {} if args.charset: for item in args.charset: key, val = item.split('=') custom_charset[key] = val generator = generate_passwords(args.min_len, args.max_len, args.pattern, custom_charset) if args.output: with open(args.output, 'w') as f: count = 0 for pwd in generator: f.write(pwd + '\n') count += 1 if count % 10000 == 0: f.flush() print(f"已生成{count}个密码,保存至{args.output}") else: # 控制台输出(不推荐大量输出) count = 0 for pwd in generator: print(pwd) count += 1 print(f"共生成{count}个密码") if __name__ == '__main__': main()
工具使用示例
- 生成长度3-4、模式为
%^@的密码并保存到文件:
python password_gen.py 3 4 -p "%^@" -o passwords.txt
- 自定义小写字符集为
abc,生成长度2的密码:
python password_gen.py 2 2 -c lower=abc -o custom.txt
总结
- 原代码慢的核心原因是递归生成器的低效、字符串拼接的冗余操作以及IO瓶颈。
- 用
itertools.product替代递归是提升效率的关键,它借助C实现的优势大幅降低CPU开销。 - 优化IO操作(批量写入)和字符串处理(用
join)可进一步提升整体速度。 - 扩展后的工具实现了Crunch的核心功能,支持长度范围、模式匹配、自定义字符集和文件输出。
内容的提问来源于stack exchange,提问作者user14492304
相关产品推荐
相关产品推荐

