Python 命令行之旅 —— 深刻 argparse (一)


做者:HelloGitHub-Prodesire
python

HelloGitHub 的《講解開源項目》系列,項目地址:github.com/HelloGitHub…git

前言

在第一篇「初探 argparse」的文章中,咱們初步掌握了使用 argparse 的四部曲,對它有了一個基本的體感。 可是它具體支持哪些類型的參數?這些參數該如何配置?本文將帶你深刻了解 argparse 的參數們。github

本系列文章默認使用 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?bash

參數動做 被分紅了以下 8 個類別:app

  • 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_truestore_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 —— 打印解析器中全部選項和參數的完整幫助信息,而後退出。ui

  • 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 所支持的參數類型多種多樣,能夠是 intfloatbool等,好比:

>>> 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)
複製代碼

位置參數

位置參數 就是經過位置而非是 --- 開頭的參數來指定參數值。

好比,咱們能夠指定兩個位置參數 xy ,先添加的 x 位於第一個位置,後加入的 y 位於第二個位置。那麼在命令行中輸入 1 2的時候,分別對應到的就是 xy

>>> parser.add_argument('x')
>>> parser.add_argument('y')
>>> parser.parse_args(['1', '2'])
Namespace(x='1', y='2')
複製代碼

可選值

可選值 就是限定參數值的內容,經過 choices 入參指定。

有些狀況下,咱們可能須要限制用戶輸入參數的內容,只能在預設的幾個值中選一個,那麼 可選值 就派上了用場。

好比,指定文件讀取方式限制爲 read-onlyread-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=NN爲一個數字,則要求該參數提供 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 公衆號,獲取更多開源項目的資料和內容

『講解開源項目系列』啓動——讓對開源項目感興趣的人再也不畏懼、讓開源項目的發起者再也不孤單。跟着咱們的文章,你會發現編程的樂趣、使用和發現參與開源項目如此簡單。歡迎聯繫咱們給咱們投稿,讓更多人愛上開源、貢獻開源~

相關文章
相關標籤/搜索