簡介
本文介紹的是argparse模塊的基本使用方法,尤其詳細介紹add_argument內建方法各個參數的使用及其效果。
本文翻譯自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))
如上示例,argparse模塊的基本使用包含5個步驟:
- import模塊:import argparse
- 獲解析器對象:argparse.ArgumentParser
- 利用解析器對象內建方法,添加參數解析規則:add_argument
- 利用解析器對象內建方法,開始解析參數,獲取解析結果對象:parse_args
- 從解析結果對象中,獲取參數值:parse_args
解析器類(ArgumentParser)
在第2步中,我們通過ArgumentParser()
函數的調用獲取瞭解析器對象ArgumentParser
。
在瞭解解析器對象的各個成員之前,我們先對一段正常的說明文本進行區間劃分
# usage字段
usage: 程序名 [-h|--help] .....
# Description字段
程序功能描述
# 位置參數說明(必選)
positional arguments:
...
# 可選參數說明
optional arguments:
...
# 補充說明字段
...
例如
usage: PROG [-h] [--foo [FOO]] bar [bar ...]
bar help
positional arguments:
bar bar help
optional arguments:
-h, --help show this help message and exit
--foo [FOO] foo help
And that's how you'd foo a bar
關於位置參數與可選參數的理解,參考下一章節:添加參數解析規則
在上述的區間劃的認識下,我們再來看看解析器對象的成員及其功能
名字 | 默認值 | 功能 |
---|---|---|
prog | sys.argv[0] | -h 時顯示的程序名 |
usage | - | usage字段描述 |
description | None | description字段描述 |
epilog | None | 補充字段描述 |
parents | None | 從父(公共)解析器中繼承所有的參數選項 |
formatter_class | None | 定製說明文本的顯示風格 |
prefix_class | - | 定製前綴字符,例如前綴"-b"改爲“+b" |
add_help | True | 是否使能顯示參數 -h --help |
allow_abbrev | True | 是否支持長參數 |
fromfile_prefix_chars | None | 略 |
argument_default | None | 略 |
conflict_handler | None | 略 |
比較常用的是description,例如:
parser = argparse.ArgumentParser(description='Process some integers.')
或者
parser = argparse.ArgumentParser()
parser.descritpioin="Process some integers."
添加參數解析規則(add_argument)
add_argument是解析器類ArgumentParser的內建方法,用於向解析器添加參數解析規則
ArgumentParser.add_argument(name or flags...[, action][, nargs][, const][, default][, type]
[, choices][, required][, help][, metavar][, dest])
內建方法支持以下的關鍵字,我們會對每一個關鍵字及其效果做進一步說明
關鍵字 | 簡介 |
---|---|
name or flags | 參數名或者"-/--"開頭的選項,例如foo 或者-f, --foo |
action | 匹配到選項後的行爲 |
nargs | 選項跟隨的參數個數 |
const | 在某些action 和nargs 下,使用的固定值 |
default | 默認值 |
type | 參數類型 |
choices | 可選的參數值範圍 |
required | 選項必選or可選 |
help | 參數描述 |
metavar | 使用說明中顯示的參數名 |
dest | 選項最終在解析結果對象中的名字 |
關鍵字name or flags
關鍵字name是什麼?flags又是什麼?兩者有什麼差別?
name表示參數名,其賦值與位置順序相關,因此也叫位置參數名,命令行中必須賦值
flags表示-|--
開頭的參數名,命令行中可選參數
例如:
#可選的flags參數
parser.add_argument('-f', '--foo')
#必選的name位置參數
parser.add_argument('bar0')
parser.add_argument('bar1')
這裏假設--foo
需要帶1個參數,那麼
prog arg1 --foo arg2 arg3
- arg1 是位置參數bar0的值
- arg2 是可選參數'-f, --foo'的值
- arg3 是位置參數bar1的值
換句話來說,在輸入的命令行中,除去所有-|--
開頭的參數及其帶上的參數值之外,剩下的參數都爲位置參數,其順序依次對應使用add_argument註冊的位置參數順序。
在命令行調用中,位置參數必須賦值,即每個必選參數都要有賦值;而可選參數(-|--)
可根據需求選擇
關鍵字action
功能如其名,關鍵字action控制匹配到命令行選項後的行爲。參數解析後不是保存值就好了?我們繼續看看。
關鍵字action只支持以下值,我們稍後再詳細講解每一個值的含義:
值 | 含義 |
---|---|
store | 保存參數值 |
store_const | 與關鍵字const配合使用,保存關鍵字const的值 |
store_true | 保存值爲True |
store_false | 保存值爲False |
append | 保存多次選項值爲列表 |
append_const | 與關鍵字const配合使用,保存關鍵字const的值爲列表 |
const | 保存選項的出現次數 |
help | 效果等效於-h 和 --help |
version | 打印版本 |
store
保存參數值,這也是默認的行爲,我們看個例子:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo')
>>> parser.parse_args('--foo 1'.split())
Namespace(foo='1')
在parse_args()
之後,--foo
選項的值就保存到了parse_args()
的解析結果對象中。
我們可以這樣獲取解析結果對象的值:
args = parser.parse_args('--foo 1'.split())
print(args.foo)
總結來說,選項名成爲了解析結果對象的成員,而選項對應的值則成了成員的值
到這裏,我們存在2個疑惑:
- 當同時支持
-f
和--foo
時,生成的成員名是什麼呢?能自定義名字麼? - 當
PROG -f
這樣不需要帶參數的選項,存儲的成員值是什麼樣的呢?
不用急,我們繼續往下看
store_const
在匹配到選項後,存儲關鍵字const的值,常用於命令行中不帶參數的選項。例如:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', action='store_const', const=42)
>>> parser.parse_args(['--foo'])
Namespace(foo=42)
從上面的例子,我們可以看到,在匹配到--foo
後,對應成員foo的保存爲了const參數
的值。
但更多時候,我們不帶參數的選項更多隻是表示布爾型的開關,這時候我們可用store_true
或者store_false
store_true 和 store_false
store_true
和store_false
是一種特殊的store_const
,存儲的值類型爲布爾型True
或False
。例如:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', action='store_true')
>>> parser.add_argument('--bar', action='store_false')
>>> parser.add_argument('--baz', action='store_false')
>>> parser.parse_args('--foo --bar'.split())
Namespace(foo=True, bar=False, baz=True)
示例中有3個布爾型“開關”,可以發現有以下特點:
store_true
在匹配到命令選項後,保存爲True
;相對的,store_false
保存爲False
- 當命令行中沒匹配到開關後,例如示例中的
baz
,則保存爲store_false
的相反值True
append
把所有值保存爲一個列表,常用於支持多次選項的情況,例如:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', action='append')
>>> parser.parse_args('--foo 1 --foo 2'.split())
Namespace(foo=['1', '2'])
append_const
與store_const
非常相似,只是把值存儲爲一個列表。此時如果沒有指定關鍵字const,則默認爲None
。append_const
常用於多個不同選項值需要存儲到相同成員列表的情況。例如:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--str', dest='types', action='append_const', const=str)
>>> parser.add_argument('--int', dest='types', action='append_const', const=int)
>>> parser.parse_args('--str --int'.split())
Namespace(types=[<class 'str'>, <class 'int'>])
理解上文需要知道以下前提:
- 關鍵字dest用於指定成員名
- 參數的值可以是各種對象,包括類型對象,即示例中的str類型和int類型
在示例中,--str
的常量值是str類型,以列表形式保存到types成員;--int
的常量值是int類型,以列表形式保存到types成員
count
如果我們只需要統計選項出現的次數,此處可以用count
,例如:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--verbose', '-v', action='count')
>>> parser.parse_args(['-vvv'])
Namespace(verbose=3)
help
打印幫助信息,功能等效於-h|--help
version
打印版本信息,需要配合關鍵字version使用,例如:
>>> import argparse
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('--version', action='version', version='%(prog)s 2.0')
>>> parser.parse_args(['--version'])
PROG 2.0
關鍵字nargs
關鍵字nargs是number argumemts的縮寫,表示選項有多少個參數,其支持以下值:
值 | 含義 |
---|---|
N (an integer) | 收集N個參數到列表 |
'?' | 無參數或單個參數 |
'*' | 大於等於0個參數 |
'+' | 大於等於1個參數 |
argparse.REMAINDER | 只收集不解析 |
當沒有指定關鍵字nargs時,其實際的值取決於關鍵字action,例如當action = "store"
時,默認獲取1個參數,當action = "store_true"
時,選項不需要帶參數。
N (an integer)
此處的N
,表示一個整型數字,含義爲選項需要提供N個參數。例如:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', nargs=2)
>>> parser.add_argument('bar', nargs=1)
>>> parser.parse_args('c --foo a b'.split())
Namespace(bar=['c'], foo=['a', 'b'])
需要注意的是,當nargs = 1
時,其並不等效於關鍵字nargs的默認情況。例如:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('bar0', nargs=1)
>>> parser.add_argument('bar1')
>>> parser.parse_args('a b'.split())
Namespace(bar0=['a'], bar1='b')
可以發現,nargs = 1
時,例如bar0,其值是一個列表,一個只有1個元素的列表;而默認情況下,就是一個元素,官方稱爲item
。
'?'
nargs='?'
可以實現3種場景:
- 輸入的命令行中,選項帶參數時,值爲附帶的參數
- 輸入的命令行中,沒有改選項時,值爲關鍵字default的值
- 輸入的命令行中,有選項但沒帶參數時,值爲關鍵字const的值(只適用於可選選項(flag))
例如:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', nargs='?', const='c', default='d')
>>> parser.add_argument('bar', nargs='?', default='d')
>>> parser.parse_args(['XX', '--foo', 'YY'])
Namespace(bar='XX', foo='YY')
>>> parser.parse_args(['XX', '--foo'])
Namespace(bar='XX', foo='c')
>>> parser.parse_args([])
Namespace(bar='d', foo='d')
一個更常用的場景,是實現可選的輸入輸出文件,例如:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('infile', nargs='?', type=argparse.FileType('r'),
... default=sys.stdin)
>>> parser.add_argument('outfile', nargs='?', type=argparse.FileType('w'),
... default=sys.stdout)
>>> parser.parse_args(['input.txt', 'output.txt'])
Namespace(infile=<_io.TextIOWrapper name='input.txt' encoding='UTF-8'>,
outfile=<_io.TextIOWrapper name='output.txt' encoding='UTF-8'>)
>>> parser.parse_args([])
Namespace(infile=<_io.TextIOWrapper name='<stdin>' encoding='UTF-8'>,
outfile=<_io.TextIOWrapper name='<stdout>' encoding='UTF-8'>)
上述例子中,如果命令行沒有指定input,則使用標準輸入stdin;如果命令行沒有指定output,則使用標準輸出stdout
'*'
nargs=2
會限制一定要有2個參數,如果需要任意多個參數呢?我們可以用nargs='*'
,例如:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', nargs='*')
>>> parser.add_argument('--bar', nargs='*')
>>> parser.add_argument('baz', nargs='*')
>>> parser.parse_args('a b --foo x y --bar 1 2'.split())
Namespace(bar=['1', '2'], baz=['a', 'b'], foo=['x', 'y'])
與nargs=N
相似,最終的值是列表類型。
'+'
nargs='+'
與nargs='*'
從功能上非常相似,唯一不同的地方在於,nargs='+'
要求至少要有1個參數,否則會報錯。
'?'
,'+'
與'*'
的定義與正則表達式中的?
,+
和*
非常相似
在正則表達式中,
- ?:表示0或1個字符
- +:表示大於等於1個字符
- *:表示大於等於0個字符
我們看個例子:
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('foo', nargs='+')
>>> parser.parse_args(['a', 'b'])
Namespace(foo=['a', 'b'])
>>> parser.parse_args([])
usage: PROG [-h] foo [foo ...]
PROG: error: the following arguments are required: foo
argparse.REMAINDER
nargs=argparse.REMAINDER
常用於收集參數後傳遞給其他的命令行解析工具,其不會解析-|--
,只是收集所有選項到列表。
例如:
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('--foo')
>>> parser.add_argument('command')
>>> parser.add_argument('args', nargs=argparse.REMAINDER)
>>> print(parser.parse_args('--foo B cmd --arg1 XX ZZ'.split()))
Namespace(args=['--arg1', 'XX', 'ZZ'], command='cmd', foo='B')
上例中,argparse沒有解析args
選項的--arg1
,而是全部收集到了一個列表
關鍵字const
在關鍵字acton和關鍵字nargs中,其實已經涉及了關鍵字const的所有功能。
關鍵字const只是存儲一個常量值,在以下兩種情況下才會使用:
當使用action='store_const'
和action='append_const'
時,關鍵字const必須提供,對其他的action關鍵字時,默認值爲None
關鍵字default
有時候,選項不帶參數,或者命令行沒對應選項,這時候就可以使用默認值,而關鍵字default存儲的就是默認值。默認情況下,關鍵字default的值爲None
。例如:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', default=42)
>>> parser.parse_args(['--foo', '2'])
Namespace(foo='2')
>>> parser.parse_args([])
Namespace(foo=42)
如果關鍵字default賦值的是字符串,而關鍵字type有指定參數類型,那麼就會把字符串轉爲關鍵字type指定的類型,例如:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--length', default='10', type=int)
>>> parser.add_argument('--width', default=10.5, type=int)
>>> parser.parse_args()
Namespace(length=10, width=10.5)
如果關鍵字nargs爲?
或者*
,那麼default的值會在命令行沒有參數時使用,例如:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('foo', nargs='?', default=42)
>>> parser.parse_args(['a'])
Namespace(foo='a')
>>> parser.parse_args([])
Namespace(foo=42)
關鍵字default也提供一種特殊用法:default=argparse.SUPPRESS
。在這種情況下,如果命令行並沒有匹配的選項,那麼並不會在解析結果對象中添加選項對應的成員,例如:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', default=argparse.SUPPRESS)
>>> parser.parse_args([])
Namespace()
>>> parser.parse_args(['--foo', '1'])
Namespace(foo='1')
關鍵字type
默認情況下,argparse解析的參數默認爲字符串類型,當然也可以通過關鍵字type指定其他任何類型,例如float
,int
,甚至是文件類型file
, 例如:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('foo', type=int)
>>> parser.add_argument('bar', type=open)
>>> parser.parse_args('2 temp.txt'.split())
Namespace(bar=<_io.TextIOWrapper name='temp.txt' encoding='UTF-8'>, foo=2)
如果關鍵字type指定的是文件類型,我們還可以通過```FileType('w')以可寫形式打開文件,例如:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('bar', type=argparse.FileType('w'))
>>> parser.parse_args(['out.txt'])
Namespace(bar=<_io.TextIOWrapper name='out.txt' encoding='UTF-8'>)
關鍵字type甚至能指定爲函數,經過函數處理後的返回值作爲參數值,例如:
>>> def perfect_square(string):
... value = int(string)
... sqrt = math.sqrt(value)
... if sqrt != int(sqrt):
... msg = "%r is not a perfect square" % string
... raise argparse.ArgumentTypeError(msg)
... return value
...
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('foo', type=perfect_square)
>>> parser.parse_args(['9'])
Namespace(foo=9)
>>> parser.parse_args(['7'])
usage: PROG [-h] foo
PROG: error: argument foo: '7' is not a perfect square
關鍵字choices
當我們需要限制選項的值範圍,我們可以用關鍵字choices。關鍵字choices限定了參數值的可選列表,如果命令行提供的參數值不在列表中,則會報錯,例如:
>>> parser = argparse.ArgumentParser(prog='game.py')
>>> parser.add_argument('move', choices=['rock', 'paper', 'scissors'])
>>> parser.parse_args(['rock'])
Namespace(move='rock')
>>> parser.parse_args(['fire'])
usage: game.py [-h] {rock,paper,scissors}
game.py: error: argument move: invalid choice: 'fire' (choose from 'rock',
'paper', 'scissors')
當然,需要注意的是,關鍵字choice的值必須符合關鍵字type指定的類型。
關鍵字required
默認情況下,-f
和--foo
都是可選的,但如果需要改爲必選,可以使用關鍵字required,例如:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', required=True)
>>> parser.parse_args(['--foo', 'BAR'])
Namespace(foo='BAR')
>>> parser.parse_args([])
usage: argparse.py [-h] [--foo FOO]
argparse.py: error: option --foo is required
關鍵字help
關鍵字help是選項的說明,在-h
或者--help
時會顯示出來,例如:
>>> parser = argparse.ArgumentParser(prog='frobble')
>>> parser.add_argument('--foo', action='store_true',
... help='foo the bars before frobbling')
>>> parser.add_argument('bar', nargs='+',
... help='one of the bars to be frobbled')
>>> parser.parse_args(['-h'])
usage: frobble [-h] [--foo] bar [bar ...]
positional arguments:
bar one of the bars to be frobbled
optional arguments:
-h, --help show this help message and exit
--foo foo the bars before frobbling
當然,關鍵字help也支持格式化顯示,%(prog)s
和大部分add_argument()的關鍵字,包括%(default)s
,%(type)s
,等等,例如:
>>> parser = argparse.ArgumentParser(prog='frobble')
>>> parser.add_argument('bar', nargs='?', type=int, default=42,
... help='the bar to %(prog)s (default: %(default)s)')
>>> parser.print_help()
usage: frobble [-h] [bar]
positional arguments:
bar the bar to frobble (default: 42)
optional arguments:
-h, --help show this help message and exit
格式爲%(keyword)s
,如果需要顯示%
,就需要使用%%
還存在一種特殊情況,假設我們不希望參數顯示在--help中,我們可以用:argparse.SUPPRESS,例如:
>>> parser = argparse.ArgumentParser(prog='frobble')
>>> parser.add_argument('--foo', help=argparse.SUPPRESS)
>>> parser.print_help()
usage: frobble [-h]
optional arguments:
-h, --help show this help message and exit
關鍵字dest
argparse會把解析的結果保存成解析結果對象的屬性,但是,屬性名是什麼呢?例如,parser.add_argument(’-f', '--foo')
,解析結果是保存在屬性f
中還是foo
中?關鍵字dest就是用於定製屬性名的。
我們先了解默認情況下,屬性名是什麼?
對位置參數而言,關鍵字dest默認爲第一個參數名,例如:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('bar')
>>> parser.parse_args(['XXX'])
Namespace(bar='XXX')
對可選參數而言,關鍵字dest首選第一個出現的長參數名。如果沒有長參數,則選擇第一個短參數名。不管選擇的是長參數還是短參數,都會把-|---
給去掉,同時把名字中的-
符號替換爲_
,以符合python的變量命名規則,例如:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('-f', '--foo-bar', '--foo')
>>> parser.add_argument('-x', '-y')
>>> parser.parse_args('-f 1 -x 2'.split())
Namespace(foo_bar='1', x='2')
>>> parser.parse_args('--foo 1 -y 2'.split())
Namespace(foo_bar='1', x='2')
我們再看看,如果定製屬性名有什麼效果?
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', dest='bar')
>>> parser.parse_args('--foo XXX'.split())
Namespace(bar='XXX')
關鍵字metavar
在執行-h|--help
,顯示的幫助信息中,如何定製選項帶的參數名呢?例如:
-t T loop times
我希望修改顯示的T
爲TIMES
,更直觀。這時候我們就可以使用關鍵字metavar了。
在默認情況下,對位置參數,則會直接顯示參數名,對可選參數,則會轉爲大寫。例如:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo')
>>> parser.add_argument('bar')
>>> parser.parse_args('X --foo Y'.split())
Namespace(bar='X', foo='Y')
>>> parser.print_help()
usage: [-h] [--foo FOO] bar
positional arguments:
bar
optional arguments:
-h, --help show this help message and exit
--foo FOO
上例中,位置參數bar直接顯示爲bar,而可選參數--foo帶的參數名就轉大寫顯示FOO。
如果我們定製顯示的參數名,該怎麼做呢?
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', metavar='YYY')
>>> parser.add_argument('bar', metavar='XXX')
>>> parser.parse_args('X --foo Y'.split())
Namespace(bar='X', foo='Y')
>>> parser.print_help()
usage: [-h] [--foo YYY] XXX
positional arguments:
XXX
optional arguments:
-h, --help show this help message and exit
--foo YYY
當然,還存在一種特殊情況,就是有多個參數nargs=N
,這時候關鍵字metavar可以以列表形式提供啦,例如:
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('-x', nargs=2)
>>> parser.add_argument('--foo', nargs=2, metavar=('bar', 'baz'))
>>> parser.print_help()
usage: PROG [-h] [-x X X] [--foo bar baz]
optional arguments:
-h, --help show this help message and exit
-x X X
--foo bar baz
最後,有一點要注意的時,關鍵字metavar與關鍵字dest不一樣的地方在於,關鍵字metavar僅僅只影響-h|--help的顯示效果,關鍵dest則同時影響解析結果屬性名
獲取解析結果
在action='store'中提到:選項名成爲了解析結果對象的成員,而選項對應的值則成了成員的值,所以如果我們需要獲取解析後的結果,直接使用解析結果的成員值就好了。例如:
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('-x', dest='xyz')
>>> parser.add_argument('--foo', nargs=2, metavar=('bar', 'baz'))
>>> args = parser.parse_args("--foo a b -x c".split())
>>> print(args.foo)
>>> ['a', 'b']
>>> print(args.xyz)
>>> c