Python -- argparse(命令行与参数解析)

Python – argparse(命令行与参数解析)

Persus & Xie

在我们用脚本去处理特定的任务时,有时候需要提供一些参数,而参数又是不确定且可变的,这时我们一般会选择通过在terminal命令行中加入参数进而传递参数,根据所传递的参数进行处理。


sys.argv

在Python中,命令行的参数和C语言很类似。C语言中,main函数的原型为int main(int argc, char **argv),这里主要指linux或者MACOS平台,argc指的是命令行传递的参数个数(程序的name为第一个参数),而argv则是一个指针数组,每一个元素为指向一个命令行参数的指针。在Python里,命令行参数储存在sys.argv中,argv是一个列表,第一个元素也为程序名称。

sys.argv 实例

我们通过实例1.1理解sys.argv的运行过程。

实例1.1,创建脚本argv.py:

#!/usr/bin/python
#example 1.1
import sys
ar1 = sys.argv[0]
ar2 = sys.argv[1]
ar3 = sys.argv[1:]
ar4 = sys.argv[2:]
print(ar1)
print(ar2)
print(ar3)
print(ar4)

在terminal中运行命令:

python argv.py p e r s u s 

运行结果:

argv.py
p
['p', 'e', 'r', 's', 'u', 's']
['e', 'r', 's', 'u', 's']

在terminal中运行命令:

python argv.py persus

运行结果:

argv.py
persus
['persus']
[]

通过以上实例我们可以看出,sys将参数以列表的形式存储,列表中第一个元素为所运行程序的名字,在命令行中,各个参数以空格隔开,列表中元素类型为字符型。

但是,sys.argv需要用很多逻辑处理传入的参数,来判别各种情形,比如:传入的参数多了还是少了、是不是有效参数、等等。这些逻辑处理需要分析各种可能的情况,并将逻辑处理写入程序,在一定程度上会浪费时间精力。

argparse库,则可以帮助省去这些逻辑处理部分。

argparse 模块

argparse是Python的一个库,用于为程序提供命令行接口(Command Line Interface)。使用这个库主要由4步来完成:

  • import argparse
  • 创建 parser
  • 向parse添加位置变量和可选变量
  • 运行 parser.parse_args()

注意,每一步都是必需的,例如,如果只创建了parser,而缺少后面两步,在运行help时将不会打印帮助文档。

在执行parser.parse_args()后,会得到一个Namespace object,里面包含了从命令行中传入的参数信息。

命令行接口支持两种类型的参量:

  • Positional arguments 位置参量
  • Optional arguments 可选参量

位置参量是用户必须设置的参量,例如 cd命令后的path参数,不设置就没办法运行,它之所以叫位置参量,是因为它们在命令中传入的位置不能错,必须按照代码中加入parser 的先后顺序传入。

可选参量对于代码运行不是必须的,但是设置后可以改变程序的行为,例如对 cp 命令,-r就是可选变量,设置后可以迭代地复制整个文件夹。 在parser.add_argument()时,可选变量必须有一条或两条短线 - 作为前缀,而位置变量则没有。一般把一条短线跟一个字母作为可选变量的缩写,方便命令行传入参数。

实例1.2 在此目录下有两个文件 argv.py,argv2.py。argv2.py内容如下所示:

#!/usr/bin/python
#example 1.2
import argparse #1)导入模块
import sys
import os
parser = argparse.ArgumentParser(description='List the content of a folder') # 2)创建parser
parser.add_argument('Path', metavar='path', type=str, help='the path to list') # 3)向parse添加位置变量和可选变量
args = parser.parse_args() # 4)运行 parser.parse_args(),获得Namespace object
input_path = args.Path
# 判断传入的路径参数
if not os.path.isdir(input_path):
    print('The path specified does not exist')
    sys.exit()

print('\n'.join(os.listdir(input_path)))

在terminal中运行命令:

python argv2.py 

运行结果:

usage: argv2.py [-h] path
argv2.py: error: the following arguments are required: path

在terminal中运行命令:

python argv2.py ./

运行结果:

argv.py
argv2.py

在terminal中运行命令:

python argv2.py ./ps

运行结果:

The path specified does not exist

以上三条命令分别表示:不传入位置参数、传入正确的位置参数以及传入错误的位置参数。

可以发现,不用在代码中写入判别语句,argparse模块可以自动检测出调用时没有传入制定的path参数并准确报错。同时在usage行,还提示:可以选择提供 -h 参数查看帮助。

在terminal中运行命令:

python argv2.py -h

运行结果:

usage: argv2.py [-h] path

List the content of a folder

positional arguments:
  path        the path to list

optional arguments:
  -h, --help  show this help message and exit

打印出的帮助信息包含了该函数的调用方法,函数的用途,位置参数(必须设置的)、可选的变量等等。

设置程序的名字

默认情况下,argparse函数库把sys.argv[0],即当前被执行代码的文件名设置为程序的名字,其主要用在help文档中,但是用户也可以在创建parser时,通过设置prog参数自定义程序名。把实例1.2中第6行代码修改如下:

parser = argparse.ArgumentParser(prog='Perseus',
                                 description='List the content of a folder') 

在terminal中运行命令:

python argv2.py 

运行结果:

usage: Perseus [-h] path
Perseus: error: the following arguments are required: path

可以发现,程序的名字由原来默认的argv2.py被修改成了Perseus

设置 Usage Help

上文中,通过运行python argv2.py -h可以查看代码的帮助文档,文档的第一行即展示了代码的调用方法:usage: argv2.py [-h] path ,或者是我们自定义的程序名:usage: Perseus [-h] path. 我们也可以通过设置自定义这一行展示的内容。再次修改实例1.2中第6行代码如下:

parser = argparse.ArgumentParser(prog='Perseus', 
                                 usage='%(prog)s [options] path Displays the file under the specified path ',
                                 description='List the content of a folder')

在terminal中运行命令:

python argv2.py -h 

运行结果:

usage: Perseus [options] path Displays the file under the specified path 

List the content of a folder

positional arguments:
  path        the path to list

optional arguments:
  -h, --help  show this help message and exit
设置help中开头和末尾的文字

通过定义descriptionepilog可以自定义帮组文档开头和末尾部分的文字。修改实例1.2中的第6行:

parser = argparse.ArgumentParser(prog='Perseus', 
                                 usage='%(prog)s [options] path Displays the file under the specified path ',
                                 description='List the content of a folder',
                                epilog='Have a fun with the software')

运行结果:

usage: Perseus [options] path Displays the file under the specified path 

List the content of a folder  <<<<<<<<<<<< 改动处

positional arguments:
  path        the path to list

optional arguments:
  -h, --help  show this help message and exit

Have a fun with the software     <<<<<<<<<<<<<改动处

自定义前缀字符

在默认情况下,命令行输入代码时,传入的可选变量(optional arguments)要用短线 -作为前缀字符(prefix chars)。这个前缀字符可以通过设置prefix_chars来定义。只是这个功能很少被用到,习惯性用法依旧是短线-。继续修改实例1.2的第6行:

parser = argparse.ArgumentParser(prog='Perseus', 
                                 usage='%(prog)s [options] path Displays the file under the specified path ',
                                 description='List the content of a folder',
                                epilog='Have a fun with the software',
                                prefix_chars='+')

在运行命令时就需要更改为:

python argv2.py +h

运行结果为:

usage: Perseus [options] path Displays the file under the specified path 

List the content of a folder

positional arguments:
  path        the path to list

optional arguments:
  +h, ++help  show this help message and exit     <<<<<<<<<<<< Here

Have a fun with the software

添加参量

当程序需要传递多个参量时,我们通常会为参量设置标示,例如:

python example.py -n1 para1 -n2 para2

此命令中,para1为参量名n1传入的参数,para2为参量名n2传入的参数。当然,我们需要在程序中添加关于参量n1,n2的命令,即运用实例第7行的语句,parser.argument()函数。下文将通过实例详细描述parser.argument()函数。

实例1.3 创建一个命令行输入参数的计算器程序argv3.py,该程序可以对传的两个数据进行加减乘除运算。程序内容如下:

#!/usr/bin/python
#example 1.3
import argparse #1)导入模块
import sys
import os
parser = argparse.ArgumentParser(prog='Calculate',
                                 usage='%(prog)s [options] calculate two numbers',
                                 description='This is a calculate program') # 2)创建parser
parser.add_argument('-n1', '--value1', type=float, help='the first Number input ') # 3)向parse添加参数1,第二个数值
parser.add_argument('-n2', '--value2', type=float, help='the first Number input ') # 3)向parse添加参数2,第一个数值
parser.add_argument('-ope', '--operator',default='+', help='the Calculation of operator,+,-,*,/') # 3)向parse添加参数3,运算符号
args = parser.parse_args() # 4)运行 parser.parse_args(),获得Namespace object
print(args)
result = None
ope = args.operator
num1 = args.value1
num2 = args.value2
if ope == '+':
  result = num1 + num2
elif ope == '-':
  result = num1 - num2
elif ope == '*':
  result = num1 * num2
elif ope == '/':
  if num2 !=0:
    result = num1/num2
  else:
    print('the num2 cannot be equal to 0')
else:
  print("More algorithms please wait for updates")
print("Result:",result)

程序中,添加参数时,我们可以对参数设置默认值,default=。对参量值的类型设置是通过在parser.add_argument()设置type来确定的。如实例1.3第9行。

其中程序中对参数变量的读取索引是双横杠后的字符,如--value1,读取参数n1时,只需读取args.value1即可。

这里涉及用两个短线引导的可选变量(optional argument),它和不用短线引导的位置变量(positional argument)的区别是,在命令行传入该变量时,需要显示指定变量名,而使用两个短线引导的可选变量时,可以只输入变量的前几个字符,不需要完整输入名称。

但是对于我们所设置的--value1--value2无法对变量名进行缩减,如缩减为--val时,两个参量会混淆。

假如希望关闭可缩减变量名,可以在初始化parser时设置,allow_abbrev=False,即:

parser = argparse.ArgumentParser(prog='Calculate',
                                 allow_abbrev=False,
                                 usage='%(prog)s [options] calculate two numbers',
                                 description='This is a calculate program')

在terminal中运行命令:

python_t % python argv3.py -h

运行结果:

usage: Calculate [options] calculate two numbers

This is a calculate program

optional arguments:
  -h, --help            show this help message and exit
  -n1 VALUE1, --value1 VALUE1
                        the first Number input
  -n2 VALUE2, --value2 VALUE2
                        the first Number input
  -ope OPERATOR, --operator OPERATOR
                        the Calculation of operator,+,-,*,/

在terminal中运行命令:

python argv3.py -n1 5 -n2 6 -ope -

运行结果:

Namespace(operator='-', value1=5.0, value2=6.0)
Result: -1.0

在terminal中运行命令:

python argv3.py -n1 5 -n2 6 --o +

运行结果:

Namespace(operator='+', value1=5.0, value2=6.0)
Result: 11.0

设置每个参量在命令行读入值的数目

parser默认情况下,会给每个命令行的参量量分配它后面相邻的值,但是也可以在程序增加参量parser.add_argument()时,通过设置nargs来让这个变量读入更多的值,例如:

实例1.4 创建argv4.py,程序内容为:

#!/usr/bin/python
#example 1.4
import argparse
parser = argparse.ArgumentParser(prog='Perseus',
                                 usage='%(prog)s [options] the usage of nargs',
                                 description='This is a test program')
parser.add_argument('--inumber',type=float,nargs=3)
args = parser.parse_args()
print(args.inumber)

设置nargs=3后,该参量会强制从命令行读入3个值,假如给定的数目不够或者数目过多,就会报错,比如:

在terminal中运行命令:

python argv4.py --inumber 6 

运行结果:

usage: Perseus [options] the usage of nargs
Perseus: error: argument --inumber: expected 3 arguments

在terminal中运行命令:

python argv4.py --inumber 6 6 6

运行结果:

[6.0, 6.0, 6.0]

在某些情况下,我们某些参量的值的个数不一定是固定的,比如在模拟程序中,我们有时候需要选择不同的分布模型,比如指数分布、正态分布、gamma分布等等,对于不同分布模型,其参数个数是不同的,nargs也提供了不同的选项,?, *, +,其中:

  • ? : 读取一个值,可以不设置,默认情况是 nargs = ‘?’

  • * : 读多个值(包括0个),会被收集到一个列表中

  • + : 读取至少一个值

实例1.4第7行更改为:

parser.add_argument('--inumber',type=float,nargs='*')

在terminal中运行命令:

python argv4.py --inumber 6 6 6

运行结果:

[6.0, 6.0, 6.0]

在terminal中运行命令:

python argv4.py --inumber 6 6

运行结果:

[6.0, 6.0]

设制变量为限定范围的选择

实例1.5:创建脚本argv5.py,内容为:

#!/usr/bin/python
#example 1.5
import argparse
parser = argparse.ArgumentParser(prog='Perseus',
                                 usage='%(prog)s [options] the usage of nargs',
                                 description='This is a test program')
parser.add_argument('--ch',choices=['perseus','crux'],required=True,
                    help='you must input a chice foarm [perseus,crux]')
args = parser.parse_args()
print(args.ch)

在terminal中运行命令:

 python argv5.py -h

运行结果:

usage: Perseus [options] the usage of nargs

This is a test program

optional arguments:
  -h, --help           show this help message and exit
  --ch {perseus,crux}  you must input a chice foarm [perseus,crux]

在terminal中运行命令:

python argv5.py --ch local

运行结果:

usage: Perseus [options] the usage of nargs
Perseus: error: argument --ch: invalid choice: 'local' (choose from 'perseus', 'crux')

在terminal中运行命令:

python argv5.py --ch perseus

运行结果:

perseus

设置参量的action参数

对于可选参量,可以设置它的action参数。这个参数可以设置为如下项:

  • store将输入的值保存在Namespace 实例中。这个是默认设置,即action='store'

  • store_const当选择此项时,保存为一个常数,但是后面需要加const指定,否则会报错

  • store_true 当选择此项时,会给它绑定一个布尔值True,显示设定后绑定False

  • store_false当选择该项时,不设置绑定的是True,显式设定后绑定False

  • append保存一个列表,每次设置这个变量,都会为列表添加一个值。

  • append_const每次设置时给列表添加一个常量

  • count保存一个整数,整数的值为该参量被设置的次数

  • help显示帮助文档并退出

  • version显示程序版本并退出

实例1.6创建脚本argv6.py,内容如下:

#!/usr/bin/python
#example 1.6
import argparse
parser = argparse.ArgumentParser(prog='Perseus',
                                 usage='%(prog)s [options] the usage of action',
                                 description='This is a test program')
parser.version = '1.6'
parser.add_argument('-a', action='store')
parser.add_argument('-b', action='store_const', const=12)
parser.add_argument('-c', action='store_true')
parser.add_argument('-d', action='store_false')
parser.add_argument('-e', action='append')
parser.add_argument('-f', action='append_const', const=10)
parser.add_argument('-g', action='count')
parser.add_argument('-i', action='help')
parser.add_argument('-j', action='version')

args = parser.parse_args()

print(vars(args))

该代码将每种action分配给指定的可选参量,然后打印出它们从命令行所捕获的值。

首先,我们调用时不显示设置任何参量,以观察它们的默认值:

在terminal中运行命令:

python argv6.py

运行结果:

{'a': None, 'b': None, 'c': False, 'd': True, 'e': None, 'f': None, 'g': None}

可以发现,大多数参量的默认值均为None,除了绑定了store_truestore_false的变量,不在命令行显式设置它们时,它们默认存储的是和action相反的FalseTrue

对于设定action=store的参量,它会直接存储命令行传入的参数而不做任何修改。

在terminal中运行命令:

python argv6.py -a 6 -b -c -d -e perseus -e crux -e local -f -f -ggggg 

运行结果:

{'a': '6', 'b': 12, 'c': True, 'd': False, 'e': ['perseus', 'crux', 'local'], 'f': [10, 10], 'g': 5}

设置可选参量为必选项

有时必须为程序设定参量的具体值,就需要将可选参量设为必选项,设施方法为在parser.add_argument()中增加 required=True,示例如下,required 参数只能绑定给 optional argument 上,因此 -ch 前面的短线是必要的。此外,设置了 requireddefault 将不起作用。

parser.add_argument('-ch',
                       action='store',
                       choices=['persus', 'crux'],
                       required=True)

定义互斥的参量

互斥参量,即两个参量只能在命令行中选一个进行设置,否则将会报错。示例如下:

实例1.7创建argv7.py

#!/usr/bin/python
#example 1.7
import argparse

parser = argparse.ArgumentParser(prog='Perseus',
                                 usage='%(prog)s [options] the usage of group',
                                 description='This is a test program')
group = parser.add_mutually_exclusive_group(required=True) # 这一行创建互斥组

group.add_argument('-c', '--crux', action='store_true') # 在互斥组中加变量
group.add_argument('-p', '--perseus', action='store_true')

args = parser.parse_args()

print(vars(args))

在terminal中运行命令:

python argv7.py -c

运行结果:

{'crux': True, 'perseus': False}

在terminal中运行命令:

python argv7.py -c -p

运行结果:

usage: Perseus [options] the usage of group
Perseus: error: argument -p/--perseus: not allowed with argument -c/--crux

禁用 Auto Help

在上述中,我们经常用到传入-h参量来获取argparse自动生成的帮助文档,这个功能也是可以被禁止的,只需要在argparse.ArgumentParser()加入add_help=False

总结

本文是在学习argparse模块时所整理的内容,其基本上包括了我们在命令行传递参量时的需求。

本文参考文章为:

https://zhuanlan.zhihu.com/p/138294710

你可能感兴趣的:(python)