命令行参数,指的是程序启动时、在命令里一起传给它的那串字符串:
python 脚本.py 你好 123这里的脚本.py、你好、123,就是命令行参数。
它解决的核心问题只有一个:让程序在"无人值守"的情况下拿到外部数据。
- 不用改代码(对比"把数据写死在代码里")
- 不用人盯着(对比
input())
1. 参数从哪来:shell 与 PATH
命令不是"python 直接看到"的,中间有个中间人——shell(命令解释器),就是 PyCharm 里的"终端"。它做两步:
- 通过环境变量
PATH找到python这个程序(python3.6/python3.12); - 把命令里剩下的内容原封不动丢给
python。
你敲的: python 脚本.py 你好 123 │ └────────┴──────┘ │ ↓ shell 通过 PATH 这几个"词" 找到这个程序 原封不动塞给 python关键:对 shell 来说,
脚本.py、你好、123只是一串字符串。这串被丢给 python 的字符串,就是命令行参数。所以"命令行参数"里的参数,是传给 python 解释器的参数。
2. 从 sys.argv 到 argparse
sys.argv:能用,但别这么写
Python 用标准库sys里的sys.argv接收参数,它是一个列表:
import sys print(sys.argv)$ python test.py 你好 123 ['test.py', '你好', '123']两个要注意的点:
sys.argv[0]是脚本名本身,真正的参数从sys.argv[1]开始。- 列表里全是字符串,
'123'不是数字。
所以想做运算必须手动转换:
import sys result = int(sys.argv[1]) + 1 # 不转就 TypeError更阴险的坑:
'123' + '1'不会报错,而是拼接成'1231'。这种不报错的错误最难查。一旦参数变多、变复杂,
sys.argv的三个死穴就暴露了:
| 死穴 | 表现 |
|---|---|
| 位置靠记 | 第几个参数是什么,全靠记忆;传多传少要自己写if判断 |
| 类型手动 | 每个参数都得手动int(),还得记住哪个该转 |
| 没有说明书 | 用户不知道有哪些参数、什么顺序、哪些必填;敲错也没有友好提示 |
argparse:直接用这个
参数一复杂,就别再用sys.argv裸写了,直接用标准库argparse:
import argparse parser = argparse.ArgumentParser(description="备份脚本") parser.add_argument('--src', required=True, help='源目录') parser.add_argument('--dst', required=True, help='目标目录') parser.add_argument('--days', type=int, default=7, help='保留天数') parser.add_argument('--verbose', action='store_true', help='打印详细日志') args = parser.parse_args() print(args.src, args.dst, args.days, args.verbose)它一次解决了sys.argv的所有痛点:
| 能力 | 写法 | 作用 |
|---|---|---|
| 名字 | --src | 用args.src取值,不用记位置 |
| 类型 | type=int | 自动做int()转换 |
| 默认值 | default=7 | 用户不传就用默认值 |
| 开关 | action='store_true' | 敲了是True,不敲是False |
| 帮助 | help='...' | 自动生成-h帮助信息 |
| 校验 | required=True | 缺参数或类型不对,自动报错 |
3. 两类参数:位置参数 vs 可选参数
argparse里的参数分两类,看add_argument的第一个参数带不带--就能区分:
不带--(位置参数) | 带--(可选参数) | |
|---|---|---|
| 怎么识别 | 靠位置(第几个) | 靠名字(--days) |
| 能不能不传 | 通常必须传 | 可以不传(有默认值) |
| 顺序 | 不能乱 | 随便 |
| 适合装什么 | 程序最核心、不给就没法干活的输入 | 配置项、开关这类次要信息 |
parser.add_argument('filename') # 不带 -- → 位置参数(必填) parser.add_argument('--days', type=int, default=7) # 带 -- → 可选参数(有默认值) parser.add_argument('--verbose', action='store_true') # 带 -- → 可选参数(开关)$ python test.py 报告.txt → 报告.txt 7 False $ python test.py 报告.txt --days 30 → 报告.txt 30 False $ python test.py → 报错:the following arguments are required: filename4. 延伸
单横杠 vs 双横杠
| 写法 | 叫法 | 特点 |
|---|---|---|
-h | 短选项 | 一个横杠 + 通常一个字母,打字快 |
--help | 长选项 | 两个横杠 + 一个单词,看得懂 |
它们常常是同一个参数的两种写法,一次就能把两个名字绑给同一个参数:
parser.add_argument('-v', '--verbose', action='store_true')于是下面三种敲法效果完全一样:
python test.py -v python test.py --verbose python test.py -v --verbose注意:判断"位置参数 vs 可选参数"看的是有没有横杠,不是有几个横杠。-v和--verbose都是可选参数。另外,短选项可以合并:-abc等价于-a -b -c。
不是 Python 独有的:git / docker 同理
命令行参数是所有命令行程序共用的通用约定(来自 Unix / POSIX)。git是 C 写的、docker是 Go 写的,但命令行长相一样:
git commit -m "修复登录bug" │ │ │ │ │ │ │ └── 可选参数 -m 的值 │ │ └── 可选参数(短选项) │ └── 位置参数(子命令) └── 程序名语言不同,约定相同——每个语言只是各有一个解析这套参数的工具:Python 用argparse,Go 用flag/cobra,C 用getopt。学会一套,就能拆解任何命令行程序。
怎么快速读一份-h帮助
先记符号:
| 符号 | 含义 |
|---|---|
[] | 可选 |
() | 分组(通常配合|,表示这组里必须选一个) |
| | 或者 |
大写单词(QUERY) | 占位符,要填真实的值,别照抄这个词 |
读法三步:
- 读
usage行,找出必填的(没有方括号的、圆括号里的); - 看参数列表,判断每个参数要不要给值——名字后面跟大写占位符就要值,光秃秃一个名字就是开关;
- 拼命令:必填先凑齐,可选按需加。
保命技巧:拿不准就只给必填先跑一次。argparse 的报错会直接告诉你缺了哪个参数、哪个值不合法——报错信息本身就是第二份 help。
互斥组(a | b | c)从哪来
帮助里那种(--http | --service | --mock MOCK),圆括号和竖线不是手写的,是用add_mutually_exclusive_group()定义后自动渲染的:
group = parser.add_mutually_exclusive_group(required=True) group.add_argument('--http', action='store_true') group.add_argument('--service', action='store_true') group.add_argument('--mock')关键差别:普通参数挂在parser上,互斥参数挂在group上。required=True时 usage 显示(a | b | c)(必选其一);改成False就变成[a | b | c](可选,但选了也只能选一个)。
5. 总结
一条问题链
问题① 怎么让程序"无人值守"地拿到外部数据? └─► 方案:命令行参数 └─► 新问题② 参数怎么交到脚本手里? └─► 方案:sys.argv(列表 / 全是字符串) └─► 新问题③ 类型要手动转、位置靠记、没说明书 └─► 方案:argparse └─► 新概念④ 两类参数:位置参数 / 可选参数速查表
| 需求 | sys.argv | argparse |
|---|---|---|
| 取参数 | sys.argv[1](靠位置) | args.src(靠名字) |
| 类型转换 | 手动int() | type=int自动 |
| 默认值 | 自己写if | default=7 |
| 开关 | '--verbose' in sys.argv | action='store_true' |
| 帮助信息 | 无 | 自动-h |
| 参数校验 | 无,容易IndexError | 自动报错 |
命令行参数不是 Python 独有的 API,而是一套看懂任何命令行程序的通用能力:程序名 → 位置参数(子命令)→ 可选参数(-x/--xxx)→ 参数的值。