首页 > 编程笔记

Python命令行参数的解析(非常详细)

通常,我们运行 Python 项目或者脚本采用直接执行脚本的方式,但是 Python 作为一个脚本语言,在 Linux 中经常会结合 Shell 脚本使用,这个时候执行的 Python 脚本多半需要使用命令行参数传入一些变量,以更加灵活、动态地传递一些数据。

例如,运行命令:

python argv.py 1 2 3

其中1 2 3就是传递给 argv.py 的命令行参数,也就是说命令行参数是调用某个程序时除程序名外的其他参数。

命令行参数工具是常用的工具,它给使用者提供了友好的交互体验。

例如,当我们需要经常调节参数的时候,如果参数都是通过硬编码写在程序中的话,我们每次修改参数都需要修改对应的代码和逻辑,这显然不太方便。比较好的方法是把必要的待修改的参数设置成通过命令行参数传入的形式,这样我们只需要在运行的时候修改参数即可。因此,在使用 Python 开发脚本,并需要接受用户参数运行时,我们可以使用命令行传参的方式。

Python 命令行参数解析库

Python 的命令行参数解析模块主要分为两类,一种是 Python 内置的模块,主要包括 sys.argv、argparse 和 getopt,另一种是第三方模块,比较有名的是 click 模块,如图1所示。

Python 命令行参数解析模块
图1:Python 命令行参数解析模块

下面我们将简要阐述对比各模块,如表1所示,然后简单解释解析命令行参数的原理,方便大家进一步理解。

表1:命令行参数解析模块
模块 描述
sys.argv sys.argv 模块传入参数的方式比较简单,功能也比较少,该模块比较适合参数数量很少且固定的脚本。
argparse argparse 模块可以让开发人员轻松地编写用户友好的命令行接口,argparse 模块会自动生成帮助和使用手册,并在用户给程序传入无效参数时报出错误信息。
getopt getopt 模块相比 sys.argv 模块,支持长参数和短参数,以及对参数解析赋值,有很多的高级用法,因此掌握 getopt 模块相对复杂,学习成本高。
click click 模块相比其他模块的优势就是支持多个命令的嵌套和组合,可以快速构建命令行程序,但是在扩展性上就没有 argparse 模块好,需要额外安装除 click 模块以外的第三方模块。

argparse模块的使用

本文将着重讲解如何使用 argparse 模块进行命令行参数解析,argparse 模块是 Python 自带的命令行参数解析模块。在程序中定义我们需要的参数,argparse 模块会从 sys.argv 模块解析出这些参数。

使用 argparse 模块的步骤如下:

1) 创建一个解析器

通过 argparse 模块中的 ArgumentParser() 方法创建一个 ArgumentParser 对象,ArgumentParser 对象包含将命令行解析成 Python 数据类型所需的全部信息。示例如下:

parse = argparse.ArgumentParser(prog='argument.py',description='编写命令行的示例文件')

ArgumentParser() 方法其他参数如表2所示其中大部分参数不常用到。

表2:ArgumentParser() 方法的参数
参数 描述
prog 程序名,默认为 sys.argv[0]。
usage 描述程序用途的字符串,默认值从添加到解析器的参数生成。
description 在参数帮助文档之前显示的文本。
parents 一个 ArgumentParser 对象的列表,它们的参数应包含在内。
formatter_class 用于自定义帮助文档输出格式的类。
prefix_chars 可选参数的前缀字符集合,默认为-
fromfile_prefix_chars 当需要从文件中读取其他参数时,用于标识文件名的前缀字符集合。
argument_default 参数的全局默认值。
conflict_handler 解决冲突选项的策略(通常不必要)。
add_help 为解析器添加一个-h/--help选项,默认为 True。
allow_abbrev 如果缩写是无歧义的,则允许缩写长选项,默认为 True。

2) 添加参数

给 ArgumentParser 对象添加参数是通过调用 add_argument() 方法完成的。示例如下:
parse.add_argument('name',type=str,help='名字') # 添加位置参数(必选)
parse.add_argument('age',type=int,help='年龄') # 添加位置参数(必选)
parse.add_argument('-s',dest='--sex',type=str,help='性别') # 添加可选参数
其中,add_argument() 方法更多的可选参数如表3所示。

表3:add_argument() 方法的参数
参数 描述
name or flags 选项字符串的名字或者列表,如 foo、-f 或 --foo。
action 在命令行使用该参数时采取的基本动作类型。
nargs 应该读取的命令行参数数量。
const 某些 action 和 nargs 要求的常数值。
default 如果命令行中没有出现该参数时,该参数的默认值。
type 命令行参数应该转换的类型。
choices 参数可允许的值的容器。
required 表示该命令行参数是否可以省略(只针对可选参数)。
help 参数的简短描述。
metavar 参数在帮助信息中的名称。
dest 给 parse_args() 返回的对象要添加的属性名称。

此处,我们重点讲解下必选参数、可选参数、默认值、参数类型、可选值、参数数量、参数传递等几个常用功能的设置方法。

① 必选参数

它的定义和函数中的必填参数是一样的,即运行程序必须要的参数。如果不传入,那么程序会报错并提示。

定义必选参数的方法非常简单,我们只需要通过 add_argument() 方法传入参数的名称即可。示例如下:

parser.add_argument('param')

这样就定义了一个名为 param 的参数,我们可以通过 args.param 来访问它。假设需要运行的程序名称为 test.py,那么我们直接执行以下命令即可:

python test.py xxx

其中必选参数直接传入,不需要加上前缀。

② 可选参数

有必选参数当然就有可选参数,可选参数因为可选可不选,所以我们在使用的时候需要在参数前加上标识---

例如,我们的参数名为 param,可以定义成 -param 或者 --param,这两种方式都可以使用,也可以同时使用两种方式。示例如下:

parser.add_argument('-param', '--param')

如果要给这个可选参数一个解释或提示,方便其他人理解这个参数,那么我们可以加 help,示例如下:

parser.add_argument('-param', '--param', help='this is a param of name')

③ 默认值

如果参数很多,我们可能不希望每一个都指定一个值,而是希望可以在不指定值的时候有一个默认值。我们可以通过 default 参数实现这个需求。示例如下:

parser.add_argument('-param', '--param', default=3, help='this is a param of num')

④ 参数类型

我们可以定义参数的默认值,也可以定义它的类型。因为命令行传入的参数默认都是字符串类型,如果我们要进行数学计算,使用字符串类型还需要先转换,这很不方便。我们可以在传入参数的时候就完成类型的匹配,这样传入参数的类型不对将直接报错,不继续运行程序。

我们可以通过 type 参数实现这个需求。示例如下:

parser.add_argument('-param', '--param', default=3,type=int, help='this is a param of num')

⑤ 可选值

可选值很好理解,就是我们希望限制传入参数的范围仅在几个值当中。例如,我们希望传入的值不是 0 就是 1,或者是在某几个具体的值当中,那么可以通过 choices 参数实现这个需求。

choices 参数传入的是一个列表,也就是我们的限制范围。示例如下:

parser.add_argument('-param', '--param', default=3, choices=[2,3,4], type=int, help='this is a param of num')

⑥ 参数数量

nargs 是一个非常有用的参数,可以用来说明传入的参数个数。例如,+表示传入至少1个参数;2表示必须传入2个参数,在程序运行时,这2个参数的值会以列表的形式赋给 param。

parser.add_argument('-param', '--param', nargs=2, type=int, help='this is a param of num')

⑦ 参数传递

dest 参数用于指定后面的参数传递给谁,在 dest 参数定义后的程序中,我们可以使用 dest 指定的参数名获取对应的值。示例如下:
parser.add_argument('-param', '--param', dest = 'port')
args = parser.parse_args()
server_port = args.port # 通过dest参数指定的port获取。

3) 解析参数

通过 parse_args() 方法将参数字符串转换为对象,并将其设为命名空间的属性,返回带有成员的命名空间:

ArgumentParser.parse_args(args=None, namespace=None)

其中,args 表示要解析的字符串列表,默认值从 sys.argv 获取;namespace 用于获取属性的对象,默认值是一个新的空 Namespace 对象。

注意,可选参数的参数和参数值可以作为两个单独参数传入。对于长参数,参数和参数值可以作为单个命令行参数传入,使用=分隔它们;对于短参数,参数和参数值可以拼接在一起。

示例如下:
parser = argparse.ArgumentParser(prog='PROG')
parser.add_argument('-x')
parser.add_argument('--foo')
parser.add_argument('bar')
print(parser.parse_args(['--foo=FOO', '-xX', 'bar']))
另外,当短参数看起来像负数时,解析器会将命令行中所有的负数参数解析为短参数。

位置参数只有在是负数并且解析器中没有任何参数看起来像负数时,才能以-开头。如果必须使用以-开头的位置参数,我们可以插入伪参数--告诉 parse_args() 在那之后的内容是位置参数。示例如下:
parser = argparse.ArgumentParser(prog='PROG')
parser.add_argument('-1', dest='one')
parser.add_argument('foo', nargs=1)
parser.add_argument('bar', nargs=1)
print(parser.parse_args(['-1', 'X', '--', '-2', '-3']))
图2中展示的是一个综合示例,演示了一个简单登录的验证和提示语。

Python 命令行参数解析综合示例
图2:Python 命令行参数解析综合示例

推荐阅读