Python 命令行之旅 —— 深入 argparse (一)
- 2019 年 10 月 3 日
- 筆記
作者:HelloGitHub-Prodesire
HelloGitHub 的《講解開源項目》系列,項目地址:https://github.com/HelloGitHub-Team/Article
前言
在第一篇「初探 argparse」的文章中,我們初步掌握了使用 argparse
的四部曲,對它有了一個基本的體感。
但是它具體支援哪些類型的參數?這些參數該如何配置?本文將帶你深入了解 argparse
的參數們。
本系列文章默認使用 Python 3 作為解釋器進行講解。 若你仍在使用 Python 2,請注意兩者之間語法和庫的使用差異哦~
參數動作
你是否還記得?在上一篇四部曲中的第二步是定義參數,在這個步驟中,我們指定了 action
入參:
parser.add_argument('--sum', dest='accumulate', action='store_const', const=sum, default=max, help='sum the nums (default: find the max)')
那麼這裡面的 action
,也就是 參數動作
,究竟是用來做什麼的呢?
想像一下,當我們在命令行輸入一串參數後,對於不同類型的參數是希望做不同的處理的。
那麼 參數動作
其實就是告訴解析器,我們希望對應的參數該被如何處理。比如,參數值是該被存成一個值呢,還是追加到一個列表中?是當成布爾的 True 呢,還是 False?
參數動作
被分成了如下 8 個類別:
store
—— 保存參數的值,這是默認的參數動作。它通常用於給一個參數指定值,如指定名字:
>>> parser.add_argument('--name') >>> parser.parse_args(['--name', 'Eric']) Namespace(name='Eric')
store_const
—— 保存被const
命名的固定值。當我們想通過是否給定參數來起到標誌的作用,給定就取某個值,就可以使用該參數動作,如:
>>> parser.add_argument('--sum', action='store_const', const=sum) >>> parser.parse_args(['--sum']) Namespace(sum=<built-in function sum>) >>> parser.parse_args([]) Namespace(sum=None)
store_true
和store_false
—— 是store_const
的特殊情況,用來分別保存 True 和 False。如果為指定參數,則其默認值分別為 False 和 True,如:
>>> parser.add_argument('--use', action='store_true') >>> parser.add_argument('--nouse', action='store_false') >>> parser.parse_args(['--use', '--nouse']) Namespace(nouse=False, use=True) >>> parser.parse_args([]) Namespace(nouse=True, use=False)
append
—— 將參數值追加保存到一個列表中。它常常用於命令行中允許多個相同選項,如:
>>> parser.add_argument('--file', action='append') >>> parser.parse_args(['--file', 'f1', '--file', 'f2']) Namespace(file=['f1', 'f2'])
append_const
—— 將const
命名的固定值追加保存到一個列表中(const
的默認值為None
)。它常常用於將多個參數所對應的固定值都保存在同一個列表中,相應的需要dest
入參來配合,以放在同一個列表中,如:
不指定 dest
入參,則固定值保存在以參數名命名的變數中
>>> parser.add_argument('--int', action='append_const', const=int) >>> parser.add_argument('--str', action='append_const', const=str) >>> parser.parse_args(['--int', '--str']) Namespace(int=[<class 'int'>], str=[<class 'str'>])
指定 dest
入參,則固定值保存在 dest
命名的變數中
>>> parser.add_argument('--int', dest='types', action='append_const', const=int) >>> parser.add_argument('--str', dest='types', action='append_const', const=str) >>> parser.parse_args(['--int', '--str']) Namespace(types=[<class 'int'>, <class 'str'>])
count
—— 計算參數出現次數,如:
>>> parser.add_argument('--increase', '-i', action='count') >>> parser.parse_args(['--increas', '--increase']) Namespace(increase=2) >>>parser.parse_args(['-iii']) Namespace(increase=3)
-
help
—— 列印解析器中所有選項和參數的完整幫助資訊,然後退出。 -
version
—— 列印命令行版本,通過指定version
入參來指定版本,調用後退出。如:
>>> parser = argparse.ArgumentParser(prog='CMD') >>> parser.add_argument('--version', action='version', version='%(prog)s 1.0') >>> parser.parse_args(['--version']) CMD 1.0
參數類別
如果說 參數動作
定義了解析器在接收到參數後該如何處理參數,那麼 參數類別
就是告訴解析器這個參數的元資訊,也就是參數是什麼樣的。比如,參數是字元串呢?還是布爾類型呢?參數是在幾個值中可選的呢?還是可以給定值,等等。
下面,我們將逐一介紹不同類型的參數。
可選參數
可選參數
顧名思義就是參數是可以加上,或不加上。默認情況下,通過 ArgumentParser.add_argument
添加的參數就是可選參數。
我們可以通過 -
來指定短參數,也就是名稱短的參數;也可以通過 --
來指定長參數,也就是名稱長的參數。當然也可以兩個都指定。
可選參數通常用於:用戶提供一個參數以及對應值,則使用該值;若不提供,則使用默認值。如:
>>> parser.add_argument('--name', '-n') >>> parser.parse_args(['--name', 'Eric']) # 通過長參數指定名稱 Namespace(name='Eric') >>> parser.parse_args(['-n', 'Eric']) # 通過短參數指定名稱 Namespace(name='Eric') >>> parser.parse_args([]) # 不指定則默認為 None Namespace(name=None)
參數類型
參數類型
就是解析器參數值是要作為什麼類型去解析,默認情況下是 str
類型。我們可以通過 type
入參來指定參數類型。
argparse
所支援的參數類型多種多樣,可以是 int
、float
、bool
等,比如:
>>> parser.add_argument('-i', type=int) >>> parser.add_argument('-f', type=float) >>> parser.add_argument('-b', type=bool) >>> parser.parse_args(['-i', '1', '-f', '2.1', '-b', '0']) Namespace(b=False, f=2.1, i=1)
更厲害的是,type
入參還可以是可調用(callable
)對象。這就給了我們很大的想像空間,可以指定 type=open
來把參數值作為文件進行處理,也可以指定自定義函數來進行類型檢查和類型轉換。
作為文件進行處理:
>>> parser.add_argument('--file', type=open) >>> parser.parse_args(['--file', 'README.md']) Namespace(b=None, f=None, file=<_io.TextIOWrapper name='README.md' mode='r' encoding='cp936'>, i=None)
使用自定義函數進行處理,入參為參數值,需返迴轉換後的結果。
比如,對於參數 --num
,我們希望當其值小於 1 時則返回 1,大於 10 時則返回 10:
>>> def limit(string): ... num = int(string) ... if num < 1: ... return 1 ... if num > 10: ... return 10 ... return num ... >>> parser.add_argument('--num', type=limit) >>> parser.parse_args(['--num', '-1']) # num 小於1,則取1 Namespace(num=1) >>> parser.parse_args(['--num', '15']) # num 大於10,則取10 Namespace(num=10) >>> parser.parse_args(['--num', '5']) # num 在1和10之間,則取原來的值 Namespace(num=5)
參數默認值
參數默認值
用於在命令行中不傳參數值的情況下的默認取值,可通過 default
來指定。如果不指定該值,則參數默認值為 None
。
比如:
>>> parser.add_argument('-i', default=0, type=int) >>> parser.add_argument('-f', default=3.14, type=float) >>> parser.add_argument('-b', default=True, type=bool) >>> parser.parse_args([]) Namespace(b=True, f=3.14, i=0)
位置參數
位置參數
就是通過位置而非是 -
或 --
開頭的參數來指定參數值。
比如,我們可以指定兩個位置參數 x
和 y
,先添加的 x
位於第一個位置,後加入的 y
位於第二個位置。那麼在命令行中輸入 1 2
的時候,分別對應到的就是 x
和 y
:
>>> parser.add_argument('x') >>> parser.add_argument('y') >>> parser.parse_args(['1', '2']) Namespace(x='1', y='2')
可選值
可選值
就是限定參數值的內容,通過 choices
入參指定。
有些情況下,我們可能需要限制用戶輸入參數的內容,只能在預設的幾個值中選一個,那麼 可選值
就派上了用場。
比如,指定文件讀取方式限制為 read-only
和 read-write
:
>>> parser.add_argument('--mode', choices=('read-only', 'read-write')) >>> parser.parse_args(['--mode', 'read-only']) Namespace(mode='read-only') >>> parser.parse_args(['--mode', 'read']) usage: [-h] [--mode {read-only,read-write}] : error: argument --mode: invalid choice: 'read' (choose from 'read-only', 'read-write')
互斥參數
互斥參數
就是多個參數之間彼此互斥,不能同時出現。使用互斥參數首先通過 ArgumentParser.add_mutually_exclusive_group
在解析器中添加一個互斥組,然後在這個組裡添加參數,那麼組內的所有參數都是互斥的。
比如,我們希望通過命令行來告知乘坐的交通工具,要麼是汽車,要麼是公交,要麼是自行車,那麼就可以這麼寫:
>>> group = parser.add_mutually_exclusive_group() >>> group.add_argument('--car', action='store_true') >>> group.add_argument('--bus', action='store_true') >>> group.add_argument('--bike', action='store_true') >>> parser.parse_args([]) # 什麼都不乘坐 Namespace(bike=False, bus=False, car=False) >>> parser.parse_args(['--bus']) # 乘坐公交 Namespace(bike=False, bus=True, car=False) >>> parser.parse_args(['--bike']) # 騎自行車 Namespace(bike=True, bus=False, car=False) >>> parser.parse_args(['--bike', '--car']) # 又想騎車,又想坐車,那是不行的 usage: [-h] [--car | --bus | --bike] : error: argument --car: not allowed with argument --bike
可變參數列表
可變參數列表
用來定義一個參數可以有多個值,且能通過 nargs
來定義值的個數。
若 nargs=N
,N
為一個數字,則要求該參數提供 N 個值,如:
>>> parser.add_argument('--foo', nargs=2) >>> print(parser.parse_args(['--foo', 'a', 'b'])) Namespace(foo=['a', 'b']) >>> print(parser.parse_args(['--foo', 'a', 'b', 'c'])) usage: [-h] [--foo FOO FOO] : error: unrecognized arguments: c
若 nargs=?
,則要求改參數提供 0 或 1 個值,如:
>>> parser.add_argument('--foo', nargs='?') >>> parser.parse_args(['--foo']) Namespace(foo=None) >>> parser.parse_args(['--foo', 'a']) Namespace(foo='a') >>> parser.parse_args(['--foo', 'a', 'b']) usage: [-h] [--foo [FOO]] : error: unrecognized arguments: b
若 nargs=*
,則要求改參數提供 0 或多個值,如:
>>> parser.add_argument('--foo', nargs='*') >>> parser.parse_args(['--foo']) Namespace(foo=[]) >>> parser.parse_args(['--foo', 'a']) Namespace(foo=['a']) >>> parser.parse_args(['--foo', 'a', 'b', 'c', 'd', 'e']) Namespace(foo=['a', 'b', 'c', 'd', 'e'])
若 nargs=?
,則要求改參數至少提供 1 個值,如:
>>> parser.add_argument('--foo', nargs='+') >>> parser.parse_args(['--foo', 'a']) Namespace(foo=['a']) >>> parser.parse_args(['--foo']) usage: [-h] [--foo FOO [FOO ...]] : error: argument --foo: expected at least one argument
小節
在了解了參數動作和參數類別後,是不是漸漸開始對使用 argparse
胸有成竹了呢?至少,用現在學到的知識來完成簡單的命令行工具已經不再話下了。
在下一篇文章中,我們來繼續深入了解 argparse
的功能,如何修改參數前綴,如何定義參數組,如何定義嵌套的解析器,如何編寫自定義動作等,讓我們拭目以待吧~
歡迎關注 HelloGitHub 公眾號,獲取更多開源項目的資料和內容
『講解開源項目系列』啟動——讓對開源項目感興趣的人不再畏懼、讓開源項目的發起者不再孤單。跟著我們的文章,你會發現編程的樂趣、使用和發現參與開源項目如此簡單。歡迎聯繫我們給我們投稿,讓更多人愛上開源、貢獻開源~