如果你正在搜索关于 argparse
用法的解释,那么你通常会很困惑,像下面这段代码到底干了什么?解决了什么问题?为什么要用这样的代码?
import argparse parser = argparse.ArgumentParser(description='Process some integers.') parser.add_argument('integers', metavar='N', type=int, nargs='+', help='an integer for the accumulator') parser.add_argument('--sum', dest='accumulate', action='store_const', const=sum, default=max, help='sum the integers (default: find the max)') args = parser.parse_args() print(args.accumulate(args.integers))
要解释这段代码干了什么,必须先回答什么是 argv
,什么是 argc
。
如果你曾经接触 C 语言,那么你可能会见过下面的一段代码:
#include <stdio.h> int main(int argc, char * argv[]) { for (int i = 0; i < argc; i++) { printf("argv[%d]: %s\n", i, argv[i]); } return 0; }
它的运行效果是这样的:
$ gcc a.c $ ./a.out hello world argv[0]: ./a.out argv[1]: hello argv[2]: world
这又是啥?
这个问题其实很简单,有一些程序所需要的数据或者条件并不能在编写代码时就确定。打一个比方,假设你正在编写一个 Email 客户端,但是你并不知道用户要发送邮件给谁,所以在程序运行时必须通过某种途径得到收件人的地址,常见的方法有:
- 制作一个图形界面,优雅地问用户收件人是谁
- 读取硬盘上的一个文件,比方说
C:\receiver.txt
(Windows)或者/home/user/receiver.txt
(Linux/Unix),这要求用户预先把收件人的地址保存到文本文件中 - 读取环境变量(对,就是Windows用户熟悉的为 Python 设置
PATH
的界面) - 在运行程序时附加收件人的地址
我相信你一定曾使用过命令行运行过 Python 脚本,例如这样的:
python3 -v some_script.py
在这行命令中,python3
是我们要执行的程序,而它之后的所有内容都是附加给它的信息,即 -v some_script.py
是附加给 Python 程序运行时的信息。其中,-v
告诉 Python 解释器以调试模式运行,some_script.py
则指明了要运行哪个 Python 脚本文件。
这个过程由操作系统来完成,各个语言都有接口来读取附加的信息。上文的 C 程序就是通过 C 语言提供的接口,把收到的信息打印出来。C 语言已经为我们做了一定的预处理,附加信息已经从一整串字符串变成了按照空格划分的字符串列表:argc
代表这个列表有几个元素,argv[i]
代表第 i 个字符串。这些附加的信息被称之为 argument(s)
,arg
则是它的简写。
历史上 C 语言是第一个大规模流行的跨平台语言,所以之后的编程语言几乎都遵从了它的设计,Python 也是。
比如下面的 Python 代码打印了所有附加的信息:
import sys for i in range(len(sys.argv)): print('argv[' + str(i) + ']:', sys.argv[i])
它的运行效果是这样的:
$ python3 a.py hello world argv[0]: x.py argv[1]: hello argv[2]: world
这样,我们就通过 Python 所提供的接口,获取到了程序运行时用户附加的所有信息。现在我们可以回答最初的那个问题:argparse
有什么用?
试想这样一个问题,如果程序有太多的数据或者条件只能在运行时才能确定,会怎么样?例如一个发送 Email 的程序,需要知道很多的信息:
sendmail --receiver someone@example.com --sender anotherone@anotherexample.com --force-point-to-point-security --max-retry 10 --retry-interval 120
其中 receiver
代表收件人,sender
代表发件人, force-point-to-point-security
代表一定要使用安全的传输方式,max-retry
代表如果发送失败,则最多尝试的发送次数,retry-interval
代码两次发送尝试之间的间隔(秒)。
当没有 argparse
这个包时,你的代码的开始部分可能充斥着这样的逻辑:检查用户有没有提供所有必要的信息,检查是否是一个合法的邮箱地址,检查尝试次数和尝试间隔是不是数字而非含有英文字母的非法输入。这些检查太累人了,argparse
包就是为了让你从这些没有价值的工作中解放出来而诞生的,你要做的,就是告诉它,哪些参数是必须的,例如这里的 receiver
和 sender
是必须的;是字符串还是数字;还是仅仅是一个开关,例如 force-point-to-point-security
;顺便给用户一个友好的反馈,在其没有提供合理的信息时,提示他该更正和补充哪些内容。
让我们回到 Python 官方文档给出的例子,其中有四个关键的内容:
parser = argparse.ArgumentParser()
:新建了一个 Parser 来负责帮助我们处理附加的信息parser.add_argument()
:定义了一个所需要输入的参数,包括它的类型、是否可选、名称等等args = parser.parse_args()
告诉 Parser 我已经定义了所有的参数,可以帮助我进行处理了args
保存了最终所有的结果,当然了,如果用户输入的信息不对,那程序就报错并终止运行了
对于我们的 sendmail
程序来说,它的 args
可能是这样的:
{'force-point-to-point-security': True, 'max-retry': 10, 'receiver': 'someone@example.com', 'retry-interval': 120, 'sender': 'anotherone@anotherexample.com'}
这样,我们就可以方便且安全的使用用户输入的数据或条件了。