读懂参数解析之后,可以再向前一步:让参数确实控制输入、输出与校验,而不是只打印“正在处理”。下面实现一个文本行数统计工具。
先约定命令行接口
python count_lines.py notes.txt --output result.json --min-length 5 --verbose
这个命令读取 notes.txt,统计去掉首尾空白后长度至少为 5
的行,将结果写入新的
result.json,并显示处理结果。字符长度按 Python 字符串的
len 计算,不是模型 token 数。
完整实现
import argparse
import json
from pathlib import Path
def nonnegative_int(value):
try:
number = int(value)
except ValueError as exc:
raise argparse.ArgumentTypeError("必须是整数") from exc
if number < 0:
raise argparse.ArgumentTypeError("不能小于 0")
return number
def main():
parser = argparse.ArgumentParser(description="统计符合长度条件的文本行")
parser.add_argument("input", type=Path, help="UTF-8 文本文件")
parser.add_argument("--output", type=Path, default=Path("result.json"))
parser.add_argument("--min-length", type=nonnegative_int, default=1)
parser.add_argument("--verbose", action="store_true")
args = parser.parse_args()
if not args.input.is_file():
parser.error("输入路径必须是已存在的文件")
if args.input.resolve() == args.output.resolve():
parser.error("输入和输出不能是同一个文件")
try:
lines = args.input.read_text(encoding="utf-8").splitlines()
count = sum(len(line.strip()) >= args.min_length for line in lines)
result = {"total_lines": len(lines), "matched_lines": count,
"min_length": args.min_length}
with args.output.open("x", encoding="utf-8") as stream:
json.dump(result, stream, ensure_ascii=False, indent=2)
stream.write("\n")
except (OSError, UnicodeError) as exc:
parser.error(str(exc))
if args.verbose:
print(f"匹配 {count}/{len(lines)} 行,结果:{args.output}")
if __name__ == "__main__":
main()
输出使用 "x"
模式创建:如果文件已存在,程序报告错误,避免覆盖已有结果。输出目录需要预先存在。
这些参数分别承担什么职责
input 是位置参数,默认必须提供;--output
是带默认值的选项;--verbose
是布尔开关;--min-length
通过自定义转换函数同时进行整数解析和非负校验。
type=Path
只把字符串转换为路径对象,不检查文件是否存在。存在性、输入输出冲突等要求属于业务校验,必须自己补上。
选项形式也不意味着一定可以省略:add_argument 支持
required=True。此外,choices
可以限制枚举值,nargs 可以声明多个值。Python argparse
文档
用一个小输入验证行为
假设文件内容为:
hello
hi
world
执行 --min-length 5 后,total_lines 为
3,matched_lines 为
2。传入负数、缺失文件或已存在的输出路径,都应得到明确错误。
从这个工具迁移到 RAG
项目时,可以把读取文件的逻辑替换为解析、切分或建立索引,但仍保留清晰的参数约定与失败提示。
自测:为何不能只写 type=int
就认为阈值有效?因为它能排除非整数,却不能排除业务上不允许的负数。