《Python 实用项目与工具制作指南》· 3.1 实战·开发题目数据生成器
3.1 实战·开发题目数据生成器
在实际编程题目的测评场景中,通常需要多组独立的测试数据文件(如test1.in
`test10.in`)和对应的答案文件(`test1.out`test10.out
)。本节将基于之前的项目,修改gen.py
使其调用std.py
的功能,一次性生成10组独立的输入输出文件,提升工具的实用性。
一、实现思路
实现思路:
- 在
gen.py
中循环生成10组数据,每组数据单独保存为testN.in
(N为1~10)。 - 通过
import
语句导入std.py
中的calculate_answers
和save_answers
函数,直接利用其计算和保存答案的功能,避免代码重复。 - 确保文件名的规范性(如
test1.in
对应test1.out
),方便后续check.py
批量检测。
二、gen.py:调用std.py生成多组文件
1. gen.py代码
# gen.py
import random
# 导入std.py中的函数(需保证std.py与gen.py在同一目录)
from std import calculate_answers, save_answersdef generate_single_test_case(min_val=-1000, max_val=1000):"""生成单组测试数据(a, b)"""a = random.randint(min_val, max_val)b = random.randint(min_val, max_val)return (a, b)def save_single_test_case(data, case_num):"""保存单组测试数据到testN.in"""filename = f"test{case_num}.in" # 文件名格式:test1.in, test2.in...with open(filename, "w", encoding="utf-8") as f:f.write(f"{data[0]} {data[1]}\n") # 写入a和breturn filenamedef generate_multiple_cases(total_cases=10):"""生成多组测试数据及对应的答案文件"""for case_num in range(1, total_cases + 1):# 1. 生成单组输入数据test_case = generate_single_test_case()# 2. 保存输入文件(testN.in)input_file = save_single_test_case(test_case, case_num)# 3. 调用std.py的函数计算答案并保存到testN.out# 注意:calculate_answers需要接收列表形式的输入,这里用[test_case]包装answers = calculate_answers([test_case])output_file = f"test{case_num}.out"save_answers(answers, output_file)print(f"生成第{case_num}组:{input_file} 和 {output_file}")if __name__ == "__main__":generate_multiple_cases(total_cases=10)print("所有测试数据及答案文件生成完成")
2. 代码解析
- 函数拆分:将原
generate_test_data
拆分为generate_single_test_case
(生成单组数据)和generate_multiple_cases
(循环生成多组),逻辑更清晰。 - 导入复用:通过
from std import ...
导入calculate_answers
和save_answers
,直接使用std.py
的计算逻辑,确保输入输出的一致性(避免重复编写求和代码导致的错误)。 - 文件名格式化:使用f-字符串
f"test{case_num}.in"
生成文件名,保证每组输入输出文件一一对应(如test3.in
对应test3.out
)。 - 批量生成:通过
for case_num in range(1, 11)
循环生成10组数据,支持通过total_cases
参数调整数量(如生成20组)。
三、验证std.py的兼容性
由于gen.py
导入了std.py
的函数,需确保std.py
的代码无需修改即可正常工作。之前编写的std.py
中,calculate_answers
接收的是列表形式的(a, b)
元组(如[(35, 72), (-12, 49)]
),而gen.py
中通过[test_case]
(如[(35, 72)]
)包装单组数据,完全符合其参数要求,因此无需修改std.py
。
std.py
的核心代码回顾:
# std.py
def calculate_answers(test_data):"""计算每组数据的答案(a + b),返回答案列表"""answers = []for a, b in test_data:answers.append(a + b)return answersdef save_answers(answers, filename="std_ans.txt"):"""将标准答案写入文件,每行一个结果"""with open(filename, "w", encoding="utf-8") as f:for ans in answers:f.write(f"{ans}\n")
四、运行效果与文件结构
执行修改后的gen.py
,终端会输出:
生成第1组:test1.in 和 test1.out
生成第2组:test2.in 和 test2.out
...
生成第10组:test10.in 和 test10.out
所有测试数据及答案文件生成完成
此时目录下会生成20个文件:
- 输入文件:
test1.in
~test10.in
,每个文件含一行数据(如test1.in
内容为35 72
)。 - 输出文件:
test1.out
~test10.out
,每个文件含一行答案(如test1.out
内容为107
)。
六、项目优势与应用场景
- 自动化程度高:通过
gen.py
一次运行即可生成全套测试数据和答案,无需手动调用std.py
10次。 - 代码复用性强:复用
std.py
的核心函数,避免重复开发,减少逻辑不一致的风险。 - 符合测评规范:生成的
testN.in
和testN.out
格式符合编程竞赛、在线测评系统(OJ)的常见要求,便于直接用于教学或测评。
通过这次拓展,你掌握了模块间函数调用的技巧,以及批量处理文件的方法。这种思路可以直接应用到“密码管理器”(批量生成加密文件)和“活动管理系统”(批量导出报名信息)等项目中。下一节,我们将学习如何通过命令行参数进一步提升工具的灵活性(如允许用户指定生成数据的范围和数量)。现在,试着运行修改后的gen.py
,然后手动检查test1.in
和test1.out
是否匹配吧!
七、写在最后
若需要更改题目,可以直接在gen.py中修改判断数据成立的条件,在std.py中修改输出的代码,无需手动调整数据,这也太方便了!