argparse 库的使用

如果您接触过命令行的话,一定感受过命令工具的使用,会有个参数的概念,比如以列表的形式列出当前目录下的所有可见文件:ls -l。进行python开发的时候,也许最终会以命令行工具的形式工作,可能需要对命令参数进行处理,那么可以使用 sys.argv 获取命令输入的参数列表,进行分析判断做相应处理,但随着参数项增多,这种方式会越来越复杂,而本文将要介绍的 argparse 库,会使参数的管理变得优雅,下面一起看一下怎么使用吧!

本文就不用解释这个参数的概念了吧,相信您对参数这个概念有了自己的感受,开发一个属于自己的命令工具一定很酷,Let’s do it!

初步感受

本文以python3开发为例,以一个简单的示例开始,创建文件 pug.py ,代码:

import argparse
parser = argparse.ArgumentParser()
parser.parse_args()

我们运行初步感受一下:

$ python3 pug.py
$ python3 pug.py --help
usage: pug.py [-h]

optional arguments:
  -h, --help  show this help message and exit
$ python3 pug.py --verbose
usage: pug.py [-h]
pug.py: error: unrecognized arguments: --verbose
$ python3 pug.py foo
usage: pug.py [-h]
pug.py: error: unrecognized arguments: foo

看看发生了什么:

  • 直接运行文件,不加任何参数,没有任何处理;
  • 第二次执行加了参数 –help 会打印一定的帮助信息,这个帮助信息中可以看到 –help可以简写为 -h
  • 第三次和第四次执行使用了不支持的参数,打印了错误提醒;

parser.parse_args() 就是参数解析的过程。

Positional arguments 的使用

Positional arguments 怎么翻译比较好呢?看到网上有人叫它 定位参数,我咋觉得叫它 占位参数 会比较贴切呢,无所谓了,还是用它本名 Positional arguments 吧!

更改pug.py代码为:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("echo")
args = parser.parse_args()
print(args.echo)

执行看看:

$ python3 pug.py
usage: pug.py [-h] echo
pug.py: error: the following arguments are required: echo
$ python3 pug.py -h
usage: pug.py [-h] echo

positional arguments:
  echo

optional arguments:
  -h, --help  show this help message and exit
$ python3 pug.py yeah
yeah

可以看到在方法 add_argument 的帮助下 echo 成功上位,使用命令时必须为echo位置上输上点什么,它才罢休,这里可以简单地认为echo是一个必须赋值的变量。似乎少了点这个参数的帮助信息,不要紧!有方法 add_argument 的加持啥都不怕,此方法有个参数 help,为其指定内容就可以填充帮助信息了,比如这样:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("echo", help='学您说话!')
args = parser.parse_args()
print(args.echo)

运行看看:

$ python3 pug.py -h
usage: pug.py [-h] echo

positional arguments:
  echo        学您说话!

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

下面,我们不能让pug太调皮,得干点实用的事,比如让它算数,那就让它算一个指定整数的平方吧,修改代码如下:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", help='您说个数,我就能告诉您这个数的平方!')
args = parser.parse_args()
print(args.square**2)

执行一下:

$ python3 pug.py 2
Traceback (most recent call last):
  File "pug.py", line 5, in <module>
    print(args.square**2)
TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'

出错啦!为什么?因为参数默认都是字符串,小狗子pug肯定不会计算字符串的平方吧!add_argument 方法此时笑了,不用担心,它可以为您按类型解析这个参数的值,只需指定方法的参数 type 就可以了:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", help='您说个数,我就能告诉您这个数的平方!', type=int)
args = parser.parse_args()
print(args.square**2)

试一下效果:

$ python3 pug.py 2
4
$ python3 pug.py -h
usage: pug.py [-h] square

positional arguments:
  square      您说个数,我就能告诉您这个数的平方!

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

小狗子pug可以的!

Optional arguments 的使用

下面一起看一下可选参数(Optional arguments)的使用。

代码更改为:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--sleep", help='让我睡会儿,困死了!')
args = parser.parse_args()
if args.sleep:
    print('我睡着了(-_-)zzz,别打搅我!')

看一下小狗子有多懒:

$ python3 pug.py -h
usage: pug.py [-h] [--sleep SLEEP]

optional arguments:
  -h, --help     show this help message and exit
  --sleep SLEEP  让我睡会儿,困死了!
$ python3 pug.py --sleep 1
我睡着了(-_-)zzz,别打搅我!

简单来说,对于睡觉,要么睡着要么没睡,应该是二值,那可以限制这个参数 –sleep 要么 True 要么 False,方法 add_argument 提供了设置参数 action ,设置其为 store_true 即可:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--sleep", help='让我睡会儿,困死了!', action='store_true')
args = parser.parse_args()
if args.sleep:
    print('我睡着了(-_-)zzz,别打搅我!')
else:
    print('我很清醒,不想睡觉!')

逗一下小狗子pug:

$ python3 pug.py -h
usage: pug.py [-h] [--sleep]

optional arguments:
  -h, --help  show this help message and exit
  --sleep     让我睡会儿,困死了!
$ python3 pug.py --sleep 1
usage: pug.py [-h] [--sleep]
pug.py: error: unrecognized arguments: 1
$ python3 pug.py --sleep
我睡着了(-_-)zzz,别打搅我!
$ python3 pug.py
我很清醒,不想睡觉!

可以看到,运行命令时,如果指定参数 –sleep,那么这个参数值就为 True, 如果没有,那么参数值为 False。如果您了解命令行工具的使用一定会问:短参数的实现会是怎样的?其实很简单:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-s', "--sleep", help='让我睡会儿,困死了!', action='store_true')
args = parser.parse_args()
if args.sleep:
    print('我睡着了(-_-)zzz,别打搅我!')
else:
    print('我很清醒,不想睡觉!')

叫小狗子pug试一下:

$ python3 pug.py -h
usage: pug.py [-h] [-s]

optional arguments:
  -h, --help   show this help message and exit
  -s, --sleep  让我睡会儿,困死了!
$ python3 pug.py -s
我睡着了(-_-)zzz,别打搅我!

Positional arguments 和 Optional arguments 结合使用

让小狗子睡着觉算数会是咋样的,试一下:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", help='您说个数,我就能告诉您这个数的平方!', type=int)
parser.add_argument('-s', "--sleep", help='让我睡会儿,困死了!', action='store_true')
args = parser.parse_args()
answer = args.square ** 2
if args.sleep:
    print(f'我睡着了(-_-)zzz都能算数:{answer}!')
else:
    print(f'我很清醒,结果是:{answer}!')

让小狗子嚣张嚣张:

$ python3 pug.py -s 3
我睡着了(-_-)zzz都能算数:9!
$ python3 pug.py 3
我很清醒,结果是:9!
$ python3 pug.py -h
usage: pug.py [-h] [-s] square

positional arguments:
  square       您说个数,我就能告诉您这个数的平方!

optional arguments:
  -h, --help   show this help message and exit
  -s, --sleep  让我睡会儿,困死了!

小狗子很厉害呀,睡着觉都给算出结果来了,那小狗子睡觉也分状态的吧,熟睡和半睡半醒状态应该会不一样,看一下会怎么样:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", help='您说个数,我就能告诉您这个数的平方!', type=int)
parser.add_argument('-s', "--sleep", type=int, help='让我睡会儿,困死了!')
args = parser.parse_args()
answer = args.square ** 2
if args.sleep == 2:
    print(f'虽然我睡的很死,但我的耳朵好像还挺好使的的,用耳朵都能算的:{answer}!')
elif args.sleep == 1:
    print(f'半睡半醒的我当然听得清你说什么,很简单的题嘛:{answer}!')
else:
    print(f'我很清醒,结果是:{answer}!')

那我们考一下小狗子:

$ python3 pug.py 3 -s
usage: pug.py [-h] [-s SLEEP] square
pug.py: error: argument -s/--sleep: expected one argument
$ python3 pug.py 3 -s 1
半睡半醒的我当然听得清你说什么,很简单的题嘛:9!
$ python3 pug.py 3 -s 2
虽然我睡的很死,但我的耳朵好像还挺好使的的,用耳朵都能算的:9!
$ python3 pug.py 3 -s 0
我很清醒,结果是:9!
$ python3 pug.py -h
usage: pug.py [-h] [-s SLEEP] square

positional arguments:
  square                您说个数,我就能告诉您这个数的平方!

optional arguments:
  -h, --help            show this help message and exit
  -s SLEEP, --sleep SLEEP
                        让我睡会儿,困死了!
$ python3 pug.py 3
我很清醒,结果是:9!

简直了,但是这里有个问题,pug睡觉状态并不是很多,如果我们指定其它可能没有必要嘛,能不能对值进行限制呢?当然可以啦,添加参数时给定 choices 就可以啦:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", help='您说个数,我就能告诉您这个数的平方!', type=int)
parser.add_argument('-s', "--sleep", type=int, choices=[1, 2], help='让我睡会儿,困死了!')
args = parser.parse_args()
answer = args.square ** 2
if args.sleep == 2:
    print(f'虽然我睡的很死,但我的耳朵好像还挺好使的的,用耳朵都能算的:{answer}!')
elif args.sleep == 1:
    print(f'半睡半醒的我当然听得清你说什么,很简单的题嘛:{answer}!')
else:
    print(f'我很清醒,结果是:{answer}!')

看一下效果:

$ python3 pug.py 3 -s 0
usage: pug.py [-h] [-s {1,2}] square
pug.py: error: argument -s/--sleep: invalid choice: 0 (choose from 1, 2)
$ python3 pug.py -h
usage: pug.py [-h] [-s {1,2}] square

positional arguments:
  square                您说个数,我就能告诉您这个数的平方!

optional arguments:
  -h, --help            show this help message and exit
  -s {1,2}, --sleep {1,2}
                        让我睡会儿,困死了!

效果还可以,现在尝试另一种玩法,先看代码:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", help='您说个数,我就能告诉您这个数的平方!', type=int)
parser.add_argument('-s', "--sleep", action='count', help='让我睡会儿,困死了!')
args = parser.parse_args()
answer = args.square ** 2
if args.sleep == 2:
    print(f'虽然我睡的很死,但我的耳朵好像还挺好使的的,用耳朵都能算的:{answer}!')
elif args.sleep == 1:
    print(f'半睡半醒的我当然听得清你说什么,很简单的题嘛:{answer}!')
else:
    print(f'我很清醒,结果是:{answer}!')

再看一下结果:

$ python3 pug.py 3 -s
半睡半醒的我当然听得清你说什么,很简单的题嘛:9!
$ python3 pug.py 3 -ss
虽然我睡的很死,但我的耳朵好像还挺好使的的,用耳朵都能算的:9!
$ python3 pug.py 3 -sss
我很清醒,结果是:9!
$ python3 pug.py 3
我很清醒,结果是:9!

好像第三条有点问题哈,修复一下这个bug:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", help='您说个数,我就能告诉您这个数的平方!', type=int)
parser.add_argument('-s', "--sleep", action='count', help='让我睡会儿,困死了!')
args = parser.parse_args()
answer = args.square ** 2
if args.sleep >= 2:
    print(f'虽然我睡的很死,但我的耳朵好像还挺好使的的,用耳朵都能算的:{answer}!')
elif args.sleep >= 1:
    print(f'半睡半醒的我当然听得清你说什么,很简单的题嘛:{answer}!')
else:
    print(f'我很清醒,结果是:{answer}!')

再看一下这次是不是更好了:

$ python3 pug.py 3 -s
半睡半醒的我当然听得清你说什么,很简单的题嘛:9!
$ python3 pug.py 3 -ss
虽然我睡的很死,但我的耳朵好像还挺好使的的,用耳朵都能算的:9!
$ python3 pug.py 3 -sss
虽然我睡的很死,但我的耳朵好像还挺好使的的,用耳朵都能算的:9!
$ python3 pug.py 3
Traceback (most recent call last):
  File "pug.py", line 7, in <module>
    if args.sleep >= 2:
TypeError: '>=' not supported between instances of 'NoneType' and 'int'

哎呀,好像最后一个让小狗子炸锅了,稍微修理一下它(给参数指定默认值):

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", help='您说个数,我就能告诉您这个数的平方!', type=int)
parser.add_argument('-s', "--sleep", action='count', default=0, help='让我睡会儿,困死了!')
args = parser.parse_args()
answer = args.square ** 2
if args.sleep >= 2:
    print(f'虽然我睡的很死,但我的耳朵好像还挺好使的的,用耳朵都能算的:{answer}!')
elif args.sleep >= 1:
    print(f'半睡半醒的我当然听得清你说什么,很简单的题嘛:{answer}!')
else:
    print(f'我很清醒,结果是:{answer}!')

看一下是否正常了:

$ python3 pug.py 3
我很清醒,结果是:9!

OKay! 效果不错,小狗子修炼得不错了!

互斥参数

有的时候小狗子的行为是互斥的,比如睡着觉的时候不能跳舞,跳舞的时候没有在睡觉,所以呀,有的时候还需要互斥参数的使用。

使用起来并不复杂,丰富一下我们的小狗子:

import argparse
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument('-s', "--sleep", action='store_true', help='让我睡会儿,困死了!')
group.add_argument('-d', '--dance', action='store_true', help='好开心,让我跳会儿舞!')
parser.add_argument("square", help='您说个数,我就能告诉您这个数的平方!', type=int)
args = parser.parse_args()
answer = args.square ** 2

if args.sleep:
    print(f'睡觉的我依然给力,{args.square} 的平方是 {answer}!')
elif args.dance:
    print(f'跳舞的时候,我的大脑非常活跃,所以,{args.square} 的平方是 {answer}!')
else:
    print(f'{args.square} 的平方是 {answer}!')

现在小狗子点了新技能,展示一下:

$ python3 pug.py -h
usage: pug.py [-h] [-s | -d] square

positional arguments:
  square       您说个数,我就能告诉您这个数的平方!

optional arguments:
  -h, --help   show this help message and exit
  -s, --sleep  让我睡会儿,困死了!
  -d, --dance  好开心,让我跳会儿舞!
$ python3 pug.py 5
5 的平方是 25!
$ python3 pug.py -s 5
睡觉的我依然给力,5 的平方是 25!
$ python3 pug.py -d 5
跳舞的时候,我的大脑非常活跃,所以,5 的平方是 25!
$ python3 pug.py -d -s 5
usage: pug.py [-h] [-s | -d] square
pug.py: error: argument -s/--sleep: not allowed with argument -d/--dance

对了,我们应该让小狗子可以自我介绍,在初始化参数分析器的时候添加描述就好了:

import argparse
parser = argparse.ArgumentParser(description='我是一只快乐的哈巴狗,我会算整数的平方哦!而且跳着舞或者睡着觉的时候我依然可以呢!')
group = parser.add_mutually_exclusive_group()
group.add_argument('-s', "--sleep", action='store_true', help='让我睡会儿,困死了!')
group.add_argument('-d', '--dance', action='store_true', help='好开心,让我跳会儿舞!')
parser.add_argument("square", help='您说个数,我就能告诉您这个数的平方!', type=int)
args = parser.parse_args()
answer = args.square ** 2

if args.sleep:
    print(f'睡觉的我依然给力,{args.square} 的平方是 {answer}!')
elif args.dance:
    print(f'跳舞的时候,我的大脑非常活跃,所以,{args.square} 的平方是 {answer}!')
else:
    print(f'{args.square} 的平方是 {answer}!')

让它好好的自我介绍一下自己吧:

$ python3 pug.py -h
usage: pug.py [-h] [-s | -d] square

我是一只快乐的哈巴狗,我会算整数的平方哦!而且跳着舞或者睡着觉的时候我依然可以呢!

positional arguments:
  square       您说个数,我就能告诉您这个数的平方!

optional arguments:
  -h, --help   show this help message and exit
  -s, --sleep  让我睡会儿,困死了!
  -d, --dance  好开心,让我跳会儿舞!

总结

作者希望您通过与小哈巴狗的玩耍,很快学会 argparse 库的使用,我们也要像它一样快乐才好!(◐‿◑)

参考