2、命令行参数解析:使用sys.argv、argparse库、getopt库处理用户输入参数
写脚本的时候,最烦什么?我猜是每次都要改代码里的硬编码路径、IP地址、端口号。说实话,我刚入行那会儿也这么干——改一次跑一次,改到后来自己都忘了改过什么。后来我学乖了,开始用命令行参数。
命令行参数解析,说白了就是让用户在执行脚本时,通过命令行告诉脚本「我要干什么」。比如 python deploy.py --env prod --port 8080,而不是打开脚本改代码。今天我就把三种主流方法掰开揉碎讲清楚。
核心知识点一览:
- sys.argv:最原始、最灵活,适合简单场景
- argparse:Python官方推荐,功能强大,适合复杂参数
- getopt:兼容C语言风格,适合老项目迁移
2.1 sys.argv:最朴素的参数获取方式
sys.argv 是什么?就是一个列表。脚本名是 sys.argv[0],后面依次是用户传的参数。举个例子:
# demo_argv.py
import sys
print(f"脚本名:{sys.argv[0]}")
print(f"参数个数:{len(sys.argv) - 1}")
for i, arg in enumerate(sys.argv[1:], 1):
print(f"第{i}个参数:{arg}")
执行一下看看:
$ python demo_argv.py deploy prod 8080
脚本名:demo_argv.py
参数个数:3
第1个参数:deploy
第2个参数:prod
第3个参数:8080
简单吧?但问题也明显——参数顺序必须固定。你想想看,如果用户忘了顺序,把 prod 和 8080 写反了,脚本照样跑,结果全错。我在项目中遇到过这种坑,排查了半天才发现是参数顺序搞反了。
注意:sys.argv 拿到的全是字符串。如果你需要数字,记得自己转类型。比如 port = int(sys.argv[3]),不然 8080 就是个字符串,做加法会变成拼接。
什么时候用 sys.argv?我个人习惯是写一次性脚本、临时测试、或者参数不超过两三个的时候。简单粗暴,不用引入任何库。
2.2 argparse:官方推荐的参数解析利器
如果你要写一个正经的工具,别犹豫,直接用 argparse。它从 Python 2.7 开始就是标准库了,功能非常全面。
先看一个完整的例子:
# deploy.py
import argparse
def main():
parser = argparse.ArgumentParser(
description='自动化部署工具 v2.0',
epilog='示例:python deploy.py --env prod --port 8080 --verbose'
)
# 位置参数(必填)
parser.add_argument('action', choices=['deploy', 'rollback', 'status'],
help='操作类型:deploy/rollback/status')
# 可选参数
parser.add_argument('--env', '-e', default='dev',
choices=['dev', 'test', 'prod'],
help='部署环境(默认:dev)')
parser.add_argument('--port', '-p', type=int, default=8000,
help='服务端口(默认:8000)')
parser.add_argument('--verbose', '-v', action='store_true',
help='开启详细日志')
parser.add_argument('--config', '-c',
help='配置文件路径')
args = parser.parse_args()
print(f"操作:{args.action}")
print(f"环境:{args.env}")
print(f"端口:{args.port}")
print(f"详细模式:{args.verbose}")
if args.config:
print(f"配置文件:{args.config}")
if __name__ == '__main__':
main()
执行效果:
$ python deploy.py deploy --env prod --port 8080 -v
操作:deploy
环境:prod
端口:8080
详细模式:True
$ python deploy.py --help
usage: deploy.py [-h] [--env {dev,test,prod}] [--port PORT] [--verbose]
[--config CONFIG]
{deploy,rollback,status}
自动化部署工具 v2.0
positional arguments:
{deploy,rollback,status}
操作类型:deploy/rollback/status
optional arguments:
-h, --help show this help message and exit
--env {dev,test,prod}, -e {dev,test,prod}
部署环境(默认:dev)
--port PORT, -p PORT 服务端口(默认:8000)
--verbose, -v 开启详细日志
--config CONFIG, -c CONFIG
配置文件路径
示例:python deploy.py --env prod --port 8080 --verbose
看到没?自动生成了帮助信息,参数类型自动转换,还有 choices 做合法性校验。我曾经在给客户写运维工具时,用 argparse 做了几十个参数,嵌套了子命令,用户用起来非常顺手。
我的小技巧:
- 短选项(如
-p)给常用参数,长选项(如--port)给全称 - 用
type=int自动转数字,省得自己写 int() - 用
choices限制取值范围,用户输错了直接报错 - 用
action='store_true'做开关参数,传了就 True,不传就 False
2.3 getopt:老牌选手,兼容C风格
说实话,我现在很少用 getopt 了。但如果你要维护老项目,或者团队里有人习惯 C 语言的 getopt 风格,那还是得会。
getopt 的用法和 argparse 不太一样,它需要你手动处理参数列表:
# old_style.py
import sys
import getopt
def main():
# 短选项格式:'e:p:v' 表示 -e 带值、-p 带值、-v 不带值
# 长选项格式:['env=', 'port=', 'verbose'] 表示 --env 带值、--port 带值、--verbose 不带值
short_opts = 'e:p:v'
long_opts = ['env=', 'port=', 'verbose']
try:
opts, args = getopt.getopt(sys.argv[1:], short_opts, long_opts)
except getopt.GetoptError as err:
print(f"参数错误:{err}")
sys.exit(1)
env = 'dev'
port = 8000
verbose = False
for opt, val in opts:
if opt in ('-e', '--env'):
env = val
elif opt in ('-p', '--port'):
port = int(val)
elif opt in ('-v', '--verbose'):
verbose = True
print(f"环境:{env}")
print(f"端口:{port}")
print(f"详细模式:{verbose}")
# args 里是剩余的位置参数
if args:
print(f"其他参数:{args}")
if __name__ == '__main__':
main()
执行效果:
$ python old_style.py -e prod -p 8080 -v
环境:prod
端口:8080
详细模式:True
注意:getopt 不会自动生成帮助信息,也不会做类型转换。你需要自己写 int(val),自己处理异常。说白了,它就是个「半自动」的工具。
2.4 三种方案对比
| 特性 | sys.argv | argparse | getopt |
|---|---|---|---|
| 学习成本 | 极低 | 中等 | 低 |
| 自动帮助信息 | ❌ | ✅ | ❌ |
| 类型自动转换 | ❌ | ✅ | ❌ |
| 参数校验 | ❌ | ✅ | ❌ |
| 子命令支持 | ❌ | ✅ | ❌ |
| 代码量 | 少 | 中等 | 中等 |
| 适用场景 | 临时脚本 | 正式工具 | 老项目维护 |
2.5 实战建议
说了这么多,到底怎么选?我个人的经验是这样的:
- 写一次性脚本:用 sys.argv,三五行搞定,别折腾
- 写团队工具:用 argparse,自动生成帮助文档,同事用起来也方便
- 维护老项目:用 getopt,保持风格一致,别没事找事去重构
另外,有个小细节要注意——参数解析的代码最好单独写一个函数,别和业务逻辑混在一起。我见过有人把参数解析写在 main 函数里,结果想复用脚本逻辑时,还得带着一堆参数解析代码,特别别扭。
避坑指南:
我曾经在写一个批量部署脚本时,用 sys.argv 传了 8 个参数。结果上线那天,运维同事传错了顺序,把测试环境的配置部署到了生产环境……嗯,从那以后,但凡超过 3 个参数,我必用 argparse。
好了,命令行参数解析就讲到这里。记住一句话:参数解析是脚本的「门面」,用户第一眼看到的就是它。做得好了,用户觉得你专业;做得差了,用户连用都不想用。