—— argparse:专业 CLI 工具
import argparse
parser = argparse.ArgumentParser(
description="数据处理工具",
epilog="示例: python tool.py input.csv --limit 100",
)
# 位置参数(必填)
parser.add_argument("input", help="输入文件路径")
# 可选参数
parser.add_argument("-o", "--output", default="output.csv",
help="输出文件路径")
parser.add_argument("-n", "--limit", type=int, default=100,
help="处理行数限制")
parser.add_argument("-v", "--verbose", action="store_true",
help="详细输出模式")
args = parser.parse_args()
print(args.input) # 输入文件
print(args.output) # output.csv
print(args.limit) # 100
print(args.verbose) # False
import argparse
from pathlib import Path
def positive_int(value):
"""自定义类型:正整数"""
ivalue = int(value)
if ivalue <= 0:
raise argparse.ArgumentTypeError(f"{value} 不是正整数")
return ivalue
def existing_file(value):
"""自定义类型:已存在的文件"""
path = Path(value)
if not path.is_file():
raise argparse.ArgumentTypeError(f"文件不存在: {value}")
return path
parser = argparse.ArgumentParser()
# 类型转换
parser.add_argument("--count", type=int)
parser.add_argument("--rate", type=float)
parser.add_argument("--limit", type=positive_int)
# 选择列表
parser.add_argument("--format", choices=["csv", "json", "yaml"],
default="csv")
# 文件参数
parser.add_argument("input", type=existing_file)
parser.add_argument("-o", type=Path, default=Path("output.csv"))
# 计数参数
parser.add_argument("-v", "--verbose", action="count", default=0)
# -v → 1, -vv → 2, -vvv → 3
# 多值参数
parser.add_argument("--tags", nargs="+", help="一个或多个标签")
parser.add_argument("--ids", nargs=3, type=int, help="恰好3个ID")
# 互斥参数
group = parser.add_mutually_exclusive_group()
group.add_argument("--json", action="store_true", help="JSON输出")
group.add_argument("--yaml", action="store_true", help="YAML输出")
import argparse
parser = argparse.ArgumentParser(prog="mycli", description="数据管理工具")
subparsers = parser.add_subparsers(dest="command", help="可用命令")
# init 子命令
init_parser = subparsers.add_parser("init", help="初始化项目")
init_parser.add_argument("--name", required=True, help="项目名")
init_parser.add_argument("--template", choices=["basic", "advanced"],
default="basic")
# sync 子命令
sync_parser = subparsers.add_parser("sync", help="同步数据")
sync_parser.add_argument("source", help="数据源")
sync_parser.add_argument("--dry-run", action="store_true")
sync_parser.add_argument("--batch-size", type=int, default=1000)
# export 子命令
export_parser = subparsers.add_parser("export", help="导出数据")
export_parser.add_argument("--format", choices=["csv", "json"],
default="csv")
export_parser.add_argument("--output", "-o", default="export")
# 解析
args = parser.parse_args()
# mycli init --name myproject
# mycli sync database --dry-run --batch-size 500
# mycli export --format json -o data
#!/usr/bin/env python3
"""fileproc - 文件处理 CLI 工具"""
import argparse
import json
import csv
import sys
from pathlib import Path
def cmd_info(args):
"""显示文件信息"""
path = Path(args.file)
if not path.exists():
print(f"错误: {args.file} 不存在", file=sys.stderr)
sys.exit(1)
info = {
"路径": str(path.resolve()),
"类型": "目录" if path.is_dir() else "文件",
"大小": path.stat().st_size if path.is_file() else "N/A",
}
if args.json:
print(json.dumps(info, ensure_ascii=False, indent=2))
else:
for k, v in info.items():
print(f"{k}: {v}")
def cmd_convert(args):
"""CSV → JSON 转换"""
with open(args.input, encoding="utf-8-sig") as f:
reader = csv.DictReader(f)
rows = list(reader)
output = Path(args.output)
with open(output, "w", encoding="utf-8") as f:
json.dump(rows, f, ensure_ascii=False, indent=2)
print(f"转换完成: {len(rows)} 行 → {output}")
def main():
parser = argparse.ArgumentParser(
prog="fileproc",
description="文件处理 CLI 工具",
)
sub = parser.add_subparsers(dest="command")
# info 子命令
p_info = sub.add_parser("info", help="显示文件信息")
p_info.add_argument("file", help="文件路径")
p_info.add_argument("--json", action="store_true")
# convert 子命令
p_conv = sub.add_parser("convert", help="格式转换")
p_conv.add_argument("input", help="输入文件")
p_conv.add_argument("-o", "--output", default="output.json")
args = parser.parse_args()
if args.command == "info":
cmd_info(args)
elif args.command == "convert":
cmd_convert(args)
else:
parser.print_help()
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""第13课 命令行参数验证"""
import argparse
def test_basic_parse():
"""基本解析测试"""
parser = argparse.ArgumentParser()
parser.add_argument("input")
parser.add_argument("-o", "--output", default="out.txt")
parser.add_argument("-v", "--verbose", action="store_true")
args = parser.parse_args(["data.csv", "-o", "result.csv"])
assert args.input == "data.csv"
assert args.output == "result.csv"
assert args.verbose == False
print("✅ 基本解析测试通过")
def test_type_validation():
"""类型验证测试"""
parser = argparse.ArgumentParser()
parser.add_argument("--count", type=int, default=0)
parser.add_argument("--rate", type=float, default=0.0)
parser.add_argument("--format", choices=["csv", "json"], default="csv")
args = parser.parse_args(["--count", "42", "--rate", "3.14", "--format", "json"])
assert args.count == 42
assert args.rate == 3.14
assert args.format == "json"
print("✅ 类型验证测试通过")
def test_subparsers():
"""子命令测试"""
parser = argparse.ArgumentParser()
sub = parser.add_subparsers(dest="command")
init_p = sub.add_parser("init")
init_p.add_argument("--name", required=True)
sync_p = sub.add_parser("sync")
sync_p.add_argument("--dry-run", action="store_true")
args = parser.parse_args(["init", "--name", "myproject"])
assert args.command == "init"
assert args.name == "myproject"
args2 = parser.parse_args(["sync", "--dry-run"])
assert args2.command == "sync"
assert args2.dry_run == True
print("✅ 子命令测试通过")
def test_custom_type():
"""自定义类型测试"""
def positive_int(v):
iv = int(v)
if iv <= 0:
raise argparse.ArgumentTypeError(f"{v} 不是正整数")
return iv
parser = argparse.ArgumentParser()
parser.add_argument("--limit", type=positive_int, default=10)
args = parser.parse_args(["--limit", "42"])
assert args.limit == 42
print("✅ 自定义类型测试通过")
if __name__ == "__main__":
test_basic_parse()
test_type_validation()
test_subparsers()
test_custom_type()
print("\n🎉 第13课全部验证通过!")