argparse --- 命令列選項、引數和子命令的剖析器

在 3.2 版被加入.

原始碼:Lib/argparse.py

備註

雖然 argparse 是實作基本命令列應用程式時預設推薦的標準函式庫模組,但如果開發者對命令列應用程式的行為有更精確的要求,可能會發現它無法提供足夠的控制程度。當 argparse 不支援應用程式所需的行為時(例如完全停用交錯選項與位置引數的支援,或是允許以 - 開頭但可能與其他已定義選項相同的選項參數值),請參閱選擇一個命令列參數剖析函式庫以了解替代方案。


argparse 模組使得撰寫使用者友善的命令列介面變得容易。程式定義它需要什麼引數,而 argparse 會找出如何從 sys.argv 中剖析這些引數。argparse 模組也會自動產生說明和用法訊息。當使用者向程式提供無效引數時,此模組也會發出錯誤。

argparse 模組對命令列介面的支援是圍繞 argparse.ArgumentParser 的實例建構的。它是引數規格的容器,並具有適用於整個剖析器的選項:

parser = argparse.ArgumentParser(
                    prog='ProgramName',
                    description='What the program does',
                    epilog='Text at the bottom of help')

ArgumentParser.add_argument() 方法會將個別的引數規格附加到剖析器。它支援位置引數、接受值的選項以及開關旗標::

parser.add_argument('filename')           # 位置引數
parser.add_argument('-c', '--count')      # 接收一個值的選項
parser.add_argument('-v', '--verbose',
                    action='store_true')  # 開關旗標

ArgumentParser.parse_args() 方法會執行剖析器,並將擷取的資料放入一個 argparse.Namespace 物件中::

args = parser.parse_args()
print(args.filename, args.count, args.verbose)

備註

如果你在尋找如何將 optparse 程式碼升級到 argparse 的指南,請參閱升級 Optparse 程式碼

ArgumentParser 物件

class argparse.ArgumentParser(prog=None, usage=None, description=None, epilog=None, parents=[], formatter_class=argparse.HelpFormatter, prefix_chars='-', fromfile_prefix_chars=None, argument_default=None, conflict_handler='error', add_help=True, allow_abbrev=True, exit_on_error=True, *, suggest_on_error=False, color=True)

建立一個新的 ArgumentParser 物件。所有參數都應該作為關鍵字引數傳入。每個參數在下面都有更詳細的描述,簡而言之它們是:

  • prog - 程式的名稱(預設值:從 __main__ 模組屬性和 sys.argv[0] 產生)

  • usage - 描述程式用法的字串(預設值:從新增到剖析器的引數產生)

  • description - 引數說明之前要顯示的文字(預設值:無文字)

  • epilog - 引數說明之後要顯示的文字(預設值:無文字)

  • parents - 一個 ArgumentParser 物件的串列,其引數也應該被包含

  • formatter_class - 用於自訂幫助說明輸出的類別

  • prefix_chars - 前綴可選引數的字元集合(預設值:'-')

  • fromfile_prefix_chars - 前綴檔案的字元集合,額外引數將從這些檔案中讀取(預設值:None

  • argument_default - 引數的全域預設值(預設值:None

  • conflict_handler - 解決衝突可選引數的策略(通常不需要)

  • add_help - 加入一個 -h/--help 選項到剖析器(預設值:True

  • allow_abbrev - 允許長選項被縮寫,只要縮寫是無歧義的(預設值:True

  • exit_on_error - 決定 ArgumentParser 在發生錯誤時是否帶著錯誤資訊退出。(預設值:True

  • suggest_on_error - 啟用對拼錯的引數選擇和子剖析器名稱的建議(預設值:False

  • color - 允許彩色輸出(預設值:True

在 3.5 版的變更: 新增 allow_abbrev 參數。

在 3.8 版的變更: 在之前的版本中,allow_abbrev 也會停用短旗標的分組,例如以 -vv 表示 -v -v

在 3.9 版的變更: 新增 exit_on_error 參數。

在 3.14 版的變更: 新增 suggest_on_errorcolor 參數。

以下各節描述了這些參數的使用方式。

prog

預設情況下,ArgumentParser 會根據 Python 直譯器的執行方式計算要在說明訊息中顯示的程式名稱:

  • 如果傳入的引數是一個檔案,則使用 sys.argv[0]基底名稱

  • 如果傳入的引數是一個目錄或 zip 檔案,則使用 Python 直譯器名稱加上 sys.argv[0]

  • 如果使用了 -m 選項,則使用 Python 直譯器名稱加上 -m 再加上模組或套件名稱。

這個預設值幾乎都不會錯,因為它會使說明訊息與命令列上呼叫程式時所用的字串一致。然而,若要更改此預設行為,可以使用 ArgumentParserprog= 引數提供另一個值:

>>> parser = argparse.ArgumentParser(prog='myprogram')
>>> parser.print_help()
usage: myprogram [-h]

options:
 -h, --help  show this help message and exit

請注意,無論程式名稱是從 sys.argv[0]、從 __main__ 模組屬性還是從 prog= 引數決定的,都可以在說明訊息中透過 %(prog)s 格式說明符號使用。

>>> parser = argparse.ArgumentParser(prog='myprogram')
>>> parser.add_argument('--foo', help='foo of the %(prog)s program')
>>> parser.print_help()
usage: myprogram [-h] [--foo FOO]

options:
 -h, --help  show this help message and exit
 --foo FOO   foo of the myprogram program

在 3.14 版的變更: 預設的 prog 值現在會反映 __main__ 實際的執行方式,而非總是使用 os.path.basename(sys.argv[0])

usage

預設情況下,ArgumentParser 會根據它包含的引數計算出用法訊息。可以使用 usage= 關鍵字引數覆寫預設訊息:

>>> parser = argparse.ArgumentParser(prog='PROG', usage='%(prog)s [options]')
>>> parser.add_argument('--foo', nargs='?', help='foo help')
>>> parser.add_argument('bar', nargs='+', help='bar help')
>>> parser.print_help()
usage: PROG [options]

positional arguments:
 bar          bar help

options:
 -h, --help   show this help message and exit
 --foo [FOO]  foo help

%(prog)s 格式說明符號可用於在你的用法訊息中填入程式名稱。

當為主剖析器指定了自訂用法訊息時,你可能也會想考慮將 prog 引數傳給 add_subparsers(),或是將 progusage 引數傳給 add_parser() 以確保子剖析器之間的命令前綴和用法資訊一致。

description

大多數對 ArgumentParser 建構函式的呼叫會使用 description= 關鍵字引數。此引數提供程式功能和運作方式的簡短描述。在說明訊息中,這個描述會顯示在命令列用法字串和各引數的說明訊息之間。

預設情況下,該描述會被自動斷行來配合給定的空間。若要更改此行為,請參閱 formatter_class 引數。

epilog

有些程式喜歡在引數描述之後顯示程式的額外說明。可以使用 ArgumentParserepilog= 引數來指定這類文字:

>>> parser = argparse.ArgumentParser(
...     description='A foo that bars',
...     epilog="And that's how you'd foo a bar")
>>> parser.print_help()
usage: argparse.py [-h]

A foo that bars

options:
 -h, --help  show this help message and exit

And that's how you'd foo a bar

description 引數一樣,epilog= 文字預設會被自動斷行,但可以透過 ArgumentParserformatter_class 引數調整此行為。

parents

有時候多個剖析器會共用一組共同的引數。與其重複定義這些引數,不如使用一個包含所有共用引數的剖析器,並將其傳給 ArgumentParserparents= 引數。parents= 引數接受一個 ArgumentParser 物件的串列,收集它們的所有位置 action 和可選 action,並將這些 action 加入正在建構的 ArgumentParser 物件中:

>>> parent_parser = argparse.ArgumentParser(add_help=False)
>>> parent_parser.add_argument('--parent', type=int)

>>> foo_parser = argparse.ArgumentParser(parents=[parent_parser])
>>> foo_parser.add_argument('foo')
>>> foo_parser.parse_args(['--parent', '2', 'XXX'])
Namespace(foo='XXX', parent=2)

>>> bar_parser = argparse.ArgumentParser(parents=[parent_parser])
>>> bar_parser.add_argument('--bar')
>>> bar_parser.parse_args(['--bar', 'YYY'])
Namespace(bar='YYY', parent=None)

請注意,大多數父剖析器會指定 add_help=False。否則 ArgumentParser 會看到兩個 -h/--help 選項(一個在父剖析器中,一個在子剖析器中)並引發錯誤。

備註

你必須在透過 parents= 傳入剖析器之前完全初始化它們。如果你在子剖析器之後更改父剖析器,那些更改將不會反映在子剖析器中。

formatter_class

ArgumentParser 物件允許透過指定替代的格式化類別來自訂說明格式。目前有四個這樣的類別:

class argparse.RawDescriptionHelpFormatter
class argparse.RawTextHelpFormatter
class argparse.ArgumentDefaultsHelpFormatter
class argparse.MetavarTypeHelpFormatter

RawDescriptionHelpFormatterRawTextHelpFormatter 提供了對文字描述顯示方式的更多控制。預設情況下,ArgumentParser 物件會在命令列說明訊息中為 descriptionepilog 文字自動斷行:

>>> parser = argparse.ArgumentParser(
...     prog='PROG',
...     description='''this description
...         was indented weird
...             but that is okay''',
...     epilog='''
...             likewise for this epilog whose whitespace will
...         be cleaned up and whose words will be wrapped
...         across a couple lines''')
>>> parser.print_help()
usage: PROG [-h]

this description was indented weird but that is okay

options:
 -h, --help  show this help message and exit

likewise for this epilog whose whitespace will be cleaned up and whose words
will be wrapped across a couple lines

RawDescriptionHelpFormatter 作為 formatter_class= 傳入,表示 descriptionepilog 已經正確格式化,不應自動斷行:

>>> parser = argparse.ArgumentParser(
...     prog='PROG',
...     formatter_class=argparse.RawDescriptionHelpFormatter,
...     description=textwrap.dedent('''\
...         Please do not mess up this text!
...         --------------------------------
...             I have indented it
...             exactly the way
...             I want it
...         '''))
>>> parser.print_help()
usage: PROG [-h]

Please do not mess up this text!
--------------------------------
   I have indented it
   exactly the way
   I want it

options:
 -h, --help  show this help message and exit

RawTextHelpFormatter 會為所有種類的說明文字保留空白,包括引數描述。然而多個換行符號會被替換為一個。如果你希望保留多個空白行,請在換行符號之間加入空格。

ArgumentDefaultsHelpFormatter 會自動將預設值的資訊加入每個引數的說明訊息中:

>>> parser = argparse.ArgumentParser(
...     prog='PROG',
...     formatter_class=argparse.ArgumentDefaultsHelpFormatter)
>>> parser.add_argument('--foo', type=int, default=42, help='FOO!')
>>> parser.add_argument('bar', nargs='*', default=[1, 2, 3], help='BAR!')
>>> parser.print_help()
usage: PROG [-h] [--foo FOO] [bar ...]

positional arguments:
 bar         BAR! (default: [1, 2, 3])

options:
 -h, --help  show this help message and exit
 --foo FOO   FOO! (default: 42)

MetavarTypeHelpFormatter 使用每個引數的 type 引數名稱作為其值的顯示名稱(而非像一般格式化器使用 dest):

>>> parser = argparse.ArgumentParser(
...     prog='PROG',
...     formatter_class=argparse.MetavarTypeHelpFormatter)
>>> parser.add_argument('--foo', type=int)
>>> parser.add_argument('bar', type=float)
>>> parser.print_help()
usage: PROG [-h] [--foo int] float

positional arguments:
  float

options:
  -h, --help  show this help message and exit
  --foo int

prefix_chars

大多數命令列選項會使用 - 作為前綴,例如 -f/--foo。需要支援不同或額外前綴字元的剖析器,例如 +f/foo 之類的選項,可以使用 ArgumentParser 建構函式的 prefix_chars= 引數來指定:

>>> parser = argparse.ArgumentParser(prog='PROG', prefix_chars='-+')
>>> parser.add_argument('+f')
>>> parser.add_argument('++bar')
>>> parser.parse_args('+f X ++bar Y'.split())
Namespace(bar='Y', f='X')

prefix_chars= 引數預設值為 '-'。提供一個不包含 - 的字元集合會導致 -f/--foo 選項被禁止。

fromfile_prefix_chars

當處理特別長的引數串列時,有時候將引數串列保存在檔案中可能比在命令列上逐一輸入更合理。如果將 fromfile_prefix_chars= 引數傳給 ArgumentParser 建構函式,那麼剖析器會將以任何指定字元開頭的引數視為檔案,並以檔案包含的引數取代之。例如:

>>> with open('args.txt', 'w', encoding=sys.getfilesystemencoding()) as fp:
...     fp.write('-f\nbar')
...
>>> parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
>>> parser.add_argument('-f')
>>> parser.parse_args(['-f', 'foo', '@args.txt'])
Namespace(f='bar')

從檔案讀取的引數預設必須每行一個(但也請參閱 convert_arg_line_to_args()),且剖析器會將其視為與命令列上引用檔案的原始引數位於相同位置。因此在上面的範例中,運算式 ['-f', 'foo', '@args.txt'] 等同於運算式 ['-f', 'foo', '-f', 'bar']

備註

Each line is treated as a single argument, so an empty line is read as an empty string ('').

ArgumentParser 使用檔案系統編碼和錯誤處理函式來讀取包含引數的檔案。

fromfile_prefix_chars= 引數預設值為 None,意味著引數永遠不會被視為檔案參照。

在 3.12 版的變更: ArgumentParser 將讀取引數檔案的編碼和錯誤處理從預設值(例如 locale.getpreferredencoding(False)"strict")改為檔案系統編碼和錯誤處理函式。在 Windows 上引數檔案應使用 UTF-8 而非 ANSI 字碼頁編碼。

argument_default

一般而言,引數預設值可以透過將預設值傳給 add_argument() 或是透過呼叫 set_defaults() 方法並指定一組名稱—值對 (name-value pair) 來設定。然而有時候為引數指定一個剖析器層級的單一預設值可能很有用。這可以透過將 argument_default= 關鍵字引數傳給 ArgumentParser 來完成。例如若要全域地抑制 parse_args() 呼叫時的屬性建立,我們可以提供 argument_default=SUPPRESS

>>> parser = argparse.ArgumentParser(argument_default=argparse.SUPPRESS)
>>> parser.add_argument('--foo')
>>> parser.add_argument('bar', nargs='?')
>>> parser.parse_args(['--foo', '1', 'BAR'])
Namespace(bar='BAR', foo='1')
>>> parser.parse_args([])
Namespace()

allow_abbrev

當你將引數串列傳給 ArgumentParserparse_args() 方法時,它會通常會辨識為長選項的縮寫

可以透過將 allow_abbrev 設為 False 來停用此功能:

>>> parser = argparse.ArgumentParser(prog='PROG', allow_abbrev=False)
>>> parser.add_argument('--foobar', action='store_true')
>>> parser.add_argument('--foonley', action='store_false')
>>> parser.parse_args(['--foon'])
usage: PROG [-h] [--foobar] [--foonley]
PROG: error: unrecognized arguments: --foon

在 3.5 版被加入.

conflict_handler

ArgumentParser 物件不允許兩個 action 擁有相同的選項字串。預設情況下,如果嘗試建立一個使用已存在選項字串的引數,ArgumentParser 物件會引發例外:

>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('-f', '--foo', help='old foo help')
>>> parser.add_argument('--foo', help='new foo help')
Traceback (most recent call last):
 ..
ArgumentError: argument --foo: conflicting option string(s): --foo

有時候(例如使用 parents 時)直接覆寫具有相同選項字串的舊引數可能很有用。若要得到此行為,可以將值 'resolve' 提供給 ArgumentParserconflict_handler= 引數:

>>> parser = argparse.ArgumentParser(prog='PROG', conflict_handler='resolve')
>>> parser.add_argument('-f', '--foo', help='old foo help')
>>> parser.add_argument('--foo', help='new foo help')
>>> parser.print_help()
usage: PROG [-h] [-f FOO] [--foo FOO]

options:
 -h, --help  show this help message and exit
 -f FOO      old foo help
 --foo FOO   new foo help

請注意,只有當一個 action 的所有選項字串都被覆寫時,ArgumentParser 物件才會移除該 action。因此在上面的範例中,舊的 -f/--foo action 會保留為 -f action,因為只有 --foo 選項字串被覆寫。

exit_on_error

當你將無效的引數串列傳給 ArgumentParserparse_args() 方法時,它通常會向 sys.stderr 印出一個訊息並以狀態碼 2 退出。

如果使用者想要手動捕捉錯誤,可以透過將 exit_on_error 設為 False 來啟用此功能:

>>> parser = argparse.ArgumentParser(exit_on_error=False)
>>> parser.add_argument('--integers', type=int)
_StoreAction(option_strings=['--integers'], dest='integers', nargs=None, const=None, default=None, type=<class 'int'>, choices=None, help=None, metavar=None)
>>> try:
...     parser.parse_args('--integers a'.split())
... except argparse.ArgumentError:
...     print('Catching an argumentError')
...
Catching an argumentError

在 3.9 版被加入.

suggest_on_error

預設情況下,當使用者傳入無效的引數選擇或子剖析器名稱時,ArgumentParser 會帶著錯誤資訊退出,並將允許的引數選擇(如果有指定的話)或子剖析器名稱列為錯誤訊息的一部分。

如果使用者想要啟用對拼錯的引數選擇和子剖析器名稱的建議,可以透過將 suggest_on_error 設為 True 來啟用此功能。請注意,這僅適用於指定的選擇皆為字串的引數:

>>> parser = argparse.ArgumentParser(suggest_on_error=True)
>>> parser.add_argument('--action', choices=['debug', 'dryrun'])
>>> parser.parse_args(['--action', 'debugg'])
usage: tester.py [-h] [--action {debug,dryrun}]
tester.py: error: argument --action: invalid choice: 'debugg', maybe you meant 'debug'? (choose from debug, dryrun)

如果你正在撰寫需要與舊版 Python 相容的程式碼,並且想要在 suggest_on_error 可用時伺機使用它,你可以在初始化剖析器後將其設為屬性,而非使用關鍵字引數:

>>> parser = argparse.ArgumentParser(description='Process some integers.')
>>> parser.suggest_on_error = True

在 3.14 版被加入.

color

預設情況下,說明訊息會使用 ANSI 跳脫序列以彩色印出。如果你想要純文字說明訊息,可以在你的本地環境中停用它,或是透過將 color 設為 False 在引數剖析器本身停用:

>>> parser = argparse.ArgumentParser(description='Process some integers.',
...                                  color=False)
>>> parser.add_argument('--action', choices=['sum', 'max'])
>>> parser.add_argument('integers', metavar='N', type=int, nargs='+',
...                     help='an integer for the accumulator')
>>> parser.parse_args(['--help'])

請注意,當 color=True 時,彩色輸出取決於環境變數和終端機能力。然而,如果 color=False,即使設定了 FORCE_COLOR 之類的環境變數,彩色輸出也是會被停用。

備註

將 stderr 重新導向到檔案時,錯誤訊息會包含顏色代碼。若要避免此情況,請設定 NO_COLORPYTHON_COLORS 環境變數(例如 NO_COLOR=1 python script.py 2> errors.txt)。

在 3.14 版被加入.

parse_args() 方法

ArgumentParser.parse_args(args=None, namespace=None)

將引數字串轉換為物件並將它們指定為命名空間的屬性。回傳填充後的命名空間。

先前對 add_argument() 的呼叫決定了確切建立什麼物件以及如何指定它們。詳情請參閱 add_argument() 的文件。

選項值語法

parse_args() 方法支援多種方式來指定選項的值(如果它接受值的話)。在最簡單的情況下,選項和它的值作為兩個獨立的引數傳入:

>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('-x')
>>> parser.add_argument('--foo')
>>> parser.parse_args(['-x', 'X'])
Namespace(foo=None, x='X')
>>> parser.parse_args(['--foo', 'FOO'])
Namespace(foo='FOO', x=None)

對於長選項(名稱長度超過一個字元的選項),選項和值也可以作為單個命令列引數傳入,使用 = 來分隔它們:

>>> parser.parse_args(['--foo=FOO'])
Namespace(foo='FOO', x=None)

對於短選項(只有一個字元長的選項),選項和它的值可以串接在一起:

>>> parser.parse_args(['-xX'])
Namespace(foo=None, x='X')

如果只有最後一個選項需要值(或都不需要),多個短選項就可以被合併在一起、只使用一個 - 前綴:

>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('-x', action='store_true')
>>> parser.add_argument('-y', action='store_true')
>>> parser.add_argument('-z')
>>> parser.parse_args(['-xyzZ'])
Namespace(x=True, y=True, z='Z')

無效引數

在剖析命令列時,parse_args() 會檢查各種錯誤,包括有歧義的選項、無效的型別、無效的選項、錯誤的位置引數數量等。當遇到此類錯誤時,它會退出並印出錯誤及用法訊息:

>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('--foo', type=int)
>>> parser.add_argument('bar', nargs='?')

>>> # 無效型別
>>> parser.parse_args(['--foo', 'spam'])
usage: PROG [-h] [--foo FOO] [bar]
PROG: error: argument --foo: invalid int value: 'spam'

>>> # 無效選項
>>> parser.parse_args(['--bar'])
usage: PROG [-h] [--foo FOO] [bar]
PROG: error: no such option: --bar

>>> # 錯誤引數數量
>>> parser.parse_args(['spam', 'badger'])
usage: PROG [-h] [--foo FOO] [bar]
PROG: error: extra arguments found: badger

包含 - 的引數

parse_args() 方法嘗試在使用者明顯犯錯時給出錯誤,但有些情況本質上是有歧義的。例如命令列引數 -1 既可能是嘗試指定一個選項,也可能是嘗試提供一個位置引數。parse_args() 方法在此處很謹慎:位置引數只有在看起來像負數且剖析器中沒有看起來像負數的選項時,才可以用 - 開頭:

>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('-x')
>>> parser.add_argument('foo', nargs='?')

>>> # 沒有負數選項,所以 -1 是位置引數
>>> parser.parse_args(['-x', '-1'])
Namespace(foo=None, x='-1')

>>> # 沒有負數選項,所以 -1 和 -5 是位置引數
>>> parser.parse_args(['-x', '-1', '-5'])
Namespace(foo='-5', x='-1')

>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('-1', dest='one')
>>> parser.add_argument('foo', nargs='?')

>>> # 有負數選項存在,所以 -1 是選項
>>> parser.parse_args(['-1', 'X'])
Namespace(foo=None, one='X')

>>> # 有負數選項存在,所以 -2 是選項
>>> parser.parse_args(['-2'])
usage: PROG [-h] [-1 ONE] [foo]
PROG: error: no such option: -2

>>> # 有負數選項存在,所以兩個 -1 都是選項
>>> parser.parse_args(['-1', '-1'])
usage: PROG [-h] [-1 ONE] [foo]
PROG: error: argument -1: expected one argument

如果你有必須以 - 開頭且不像負數的位置引數,你可以插入偽引數 '--',它會告訴 parse_args() 在此之後的所有內容都是位置引數:

>>> parser.parse_args(['--', '-f'])
Namespace(foo='-f', one=None)

更多詳情請參閱 argparse howto 中關於有歧義引數的說明

引數縮寫 (前綴匹配)

parse_args() 方法預設允許長選項被縮寫為前綴,只要縮寫是無歧義的(前綴匹配到唯一的選項):

>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('-bacon')
>>> parser.add_argument('-badger')
>>> parser.parse_args('-bac MMM'.split())
Namespace(bacon='MMM', badger=None)
>>> parser.parse_args('-bad WOOD'.split())
Namespace(bacon=None, badger='WOOD')
>>> parser.parse_args('-ba BA'.split())
usage: PROG [-h] [-bacon BACON] [-badger BADGER]
PROG: error: ambiguous option: -ba could match -badger, -bacon

對於可能產生多個選項的引數會產生錯誤。可以透過將 allow_abbrev 設為 False 來停用此功能。

sys.argv 之外

有時候讓 ArgumentParser 剖析 sys.argv 以外的引數可能很有用。這可以透過將字串串列傳給 parse_args() 來完成。這對於在互動式提示中測試很有用:

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument(
...     'integers', metavar='int', type=int, choices=range(10),
...     nargs='+', help='an integer in the range 0..9')
>>> parser.add_argument(
...     '--sum', dest='accumulate', action='store_const', const=sum,
...     default=max, help='sum the integers (default: find the max)')
>>> parser.parse_args(['1', '2', '3', '4'])
Namespace(accumulate=<built-in function max>, integers=[1, 2, 3, 4])
>>> parser.parse_args(['1', '2', '3', '4', '--sum'])
Namespace(accumulate=<built-in function sum>, integers=[1, 2, 3, 4])

命名空間物件

class argparse.Namespace

parse_args() 預設使用的簡單類別,用來建立保存屬性的物件並回傳它。

這個類別刻意保持簡單,只是一個具有可讀字串表示的 object 子類別。如果你偏好以類字典的方式檢視屬性,可以使用標準 Python 慣用寫法 vars()

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo')
>>> args = parser.parse_args(['--foo', 'BAR'])
>>> vars(args)
{'foo': 'BAR'}

ArgumentParser 將屬性指定給已存在的物件而非新的 Namespace 物件也可能很有用。這可以透過指定 namespace= 關鍵字引數來達成:

>>> class C:
...     pass
...
>>> c = C()
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo')
>>> parser.parse_args(args=['--foo', 'BAR'], namespace=c)
>>> c.foo
'BAR'

其他工具

子命令

許多程式將其功能分割為數個子命令,例如 svn 程式可以呼叫 svn checkoutsvn updatesvn commit 等子命令。當程式執行多個需要不同種類命令列引數的不同功能時,以這種方式分割功能是特別好的做法。ArgumentParser 透過 add_subparsers() 方法支援建立這類子命令。add_subparsers() 方法通常不帶引數呼叫,並回傳一個特殊的 action 物件。此物件有一個方法 add_parser(),它接受命令名稱和任何 ArgumentParser 建構函式引數,並回傳一個可以像往常一樣修改的 ArgumentParser 物件。

參數的解釋:

  • title - 說明輸出中子剖析器群組的標題;預設情況下,若有提供 description 則為 "subcommands",否則使用位置引數的標題

  • description - 說明輸出中子剖析器群組的描述,預設為 None

  • prog - 將與子命令說明一起顯示的用法資訊,預設為程式名稱和子剖析器引數之前的任何位置引數

  • parser_class - 將用來建立子剖析器實例的類別,預設為目前剖析器的類別(例如 ArgumentParser

  • action - 在命令列遇到此引數時要執行的基本 action 類型

  • dest - 用於儲存子命令名稱的屬性名稱;預設為 None 且不儲存任何值

  • required - 是否必須提供子命令,預設為 False(在 3.7 中新增)

  • help - 說明輸出中子剖析器群組的說明,預設為 None

  • metavar - 在說明中呈現可用子命令的字串;預設為 None 並以 {cmd1, cmd2, ..} 的形式呈現子命令

一些使用範例:

>>> # 建立頂層剖析器
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('--foo', action='store_true', help='foo help')
>>> subparsers = parser.add_subparsers(help='subcommand help')
>>>
>>> # 建立 "a" 命令的剖析器
>>> parser_a = subparsers.add_parser('a', help='a help')
>>> parser_a.add_argument('bar', type=int, help='bar help')
>>>
>>> # 建立 "b" 命令的剖析器
>>> parser_b = subparsers.add_parser('b', help='b help')
>>> parser_b.add_argument('--baz', choices=('X', 'Y', 'Z'), help='baz help')
>>>
>>> # 剖析一些引數串列
>>> parser.parse_args(['a', '12'])
Namespace(bar=12, foo=False)
>>> parser.parse_args(['--foo', 'b', '--baz', 'Z'])
Namespace(baz='Z', foo=True)

請注意 parse_args() 回傳的物件只會包含主剖析器和命令列所選子剖析器的屬性(而非任何其他子剖析器)。因此在上面的範例中,當指定 a 命令時,只有 foobar 屬性存在;當指定 b 命令時,只有 foobaz 屬性存在。

If a subparser defines an argument with the same dest as the parent parser, the two share a single namespace attribute, so the parent's value won't be retained. Users should give them distinct dest values to keep both.

同樣地,當從子剖析器請求說明訊息時,只會印出該特定剖析器的說明。說明訊息不會包含父剖析器或兄弟剖析器的訊息。(然而每個子剖析器命令的說明訊息可以透過如上所述向 add_parser() 提供 help= 引數來給定。)

>>> parser.parse_args(['--help'])
usage: PROG [-h] [--foo] {a,b} ...

positional arguments:
  {a,b}   subcommand help
    a     a help
    b     b help

options:
  -h, --help  show this help message and exit
  --foo   foo help

>>> parser.parse_args(['a', '--help'])
usage: PROG a [-h] bar

positional arguments:
  bar     bar help

options:
  -h, --help  show this help message and exit

>>> parser.parse_args(['b', '--help'])
usage: PROG b [-h] [--baz {X,Y,Z}]

options:
  -h, --help     show this help message and exit
  --baz {X,Y,Z}  baz help

add_subparsers() 方法也支援 titledescription 關鍵字引數。當任一者存在時,子剖析器的命令會在說明輸出中以自己的群組出現。例如:

>>> parser = argparse.ArgumentParser()
>>> subparsers = parser.add_subparsers(title='subcommands',
...                                    description='valid subcommands',
...                                    help='additional help')
>>> subparsers.add_parser('foo')
>>> subparsers.add_parser('bar')
>>> parser.parse_args(['-h'])
usage:  [-h] {foo,bar} ...

options:
  -h, --help  show this help message and exit

subcommands:
  valid subcommands

  {foo,bar}   additional help

此外,add_parser() 支援一個額外的 aliases 引數,它允許多個字串參照同一個子剖析器。這個範例像 svn 一樣,將 co 作為 checkout 的簡寫別名:

>>> parser = argparse.ArgumentParser()
>>> subparsers = parser.add_subparsers()
>>> checkout = subparsers.add_parser('checkout', aliases=['co'])
>>> checkout.add_argument('foo')
>>> parser.parse_args(['co', 'bar'])
Namespace(foo='bar')

add_parser() 也支援一個額外的 deprecated 引數,它允許棄用子剖析器。

>>> import argparse
>>> parser = argparse.ArgumentParser(prog='chicken.py')
>>> subparsers = parser.add_subparsers()
>>> run = subparsers.add_parser('run')
>>> fly = subparsers.add_parser('fly', deprecated=True)
>>> parser.parse_args(['fly'])
chicken.py: warning: command 'fly' is deprecated
Namespace()

在 3.13 版被加入.

處理子命令的一個特別有效的方式是將 add_subparsers() 方法的使用與 set_defaults() 的呼叫結合,使每個子剖析器知道它應該執行哪個 Python 函式。例如:

>>> # 子命令函式
>>> def foo(args):
...     print(args.x * args.y)
...
>>> def bar(args):
...     print('((%s))' % args.z)
...
>>> # 建立頂層剖析器
>>> parser = argparse.ArgumentParser()
>>> subparsers = parser.add_subparsers(required=True)
>>>
>>> # 建立 "foo" 命令的剖析器
>>> parser_foo = subparsers.add_parser('foo')
>>> parser_foo.add_argument('-x', type=int, default=1)
>>> parser_foo.add_argument('y', type=float)
>>> parser_foo.set_defaults(func=foo)
>>>
>>> # 建立 "bar" 命令的剖析器
>>> parser_bar = subparsers.add_parser('bar')
>>> parser_bar.add_argument('z')
>>> parser_bar.set_defaults(func=bar)
>>>
>>> # 剖析引數並呼叫所選的函式
>>> args = parser.parse_args('foo 1 -x 2'.split())
>>> args.func(args)
2.0
>>>
>>> # 剖析引數並呼叫所選的函式
>>> args = parser.parse_args('bar XYZYX'.split())
>>> args.func(args)
((XYZYX))

這樣你可以讓 parse_args() 在引數剖析完成後負責呼叫適當的函式。像這樣將函式與 action 關聯通常是處理每個子剖析器不同動作的最簡單方式。然而如果有必要檢查被呼叫的子剖析器名稱,add_subparsers() 呼叫的 dest 關鍵字引數可以達成此目的:

>>> parser = argparse.ArgumentParser()
>>> subparsers = parser.add_subparsers(dest='subparser_name')
>>> subparser1 = subparsers.add_parser('1')
>>> subparser1.add_argument('-x')
>>> subparser2 = subparsers.add_parser('2')
>>> subparser2.add_argument('y')
>>> parser.parse_args(['2', 'frobble'])
Namespace(subparser_name='2', y='frobble')

在 3.7 版的變更: 新增 required 僅限關鍵字參數。

在 3.14 版的變更: 子剖析器的 prog 不再受主剖析器中自訂用法訊息的影響。

FileType 物件

class argparse.FileType(mode='r', bufsize=-1, encoding=None, errors=None)

FileType 工廠建立可以傳給 ArgumentParser.add_argument() 的 type 引數的物件。以 FileType 物件作為其型別的引數會以請求的模式、緩衝區大小、編碼和錯誤處理開啟命令列引數作為檔案(更多詳情請參閱 open() 函式):

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--raw', type=argparse.FileType('wb', 0))
>>> parser.add_argument('out', type=argparse.FileType('w', encoding='UTF-8'))
>>> parser.parse_args(['--raw', 'raw.dat', 'file.txt'])
Namespace(out=<_io.TextIOWrapper name='file.txt' mode='w' encoding='UTF-8'>, raw=<_io.FileIO name='raw.dat' mode='wb'>)

FileType 物件能理解偽引數 '-',並自動將其轉換為可讀 FileType 物件的 sys.stdin 和可寫 FileType 物件的 sys.stdout

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('infile', type=argparse.FileType('r'))
>>> parser.parse_args(['-'])
Namespace(infile=<_io.TextIOWrapper name='<stdin>' encoding='UTF-8'>)

備註

如果一個引數使用了 FileType 然後後續的引數失敗了,雖然會報告錯誤但檔案不會自動關閉。這也可能覆蓋輸出檔案。在這種情況下,最好等到剖析器執行完畢後,再使用 with 陳述式來管理檔案。

在 3.4 版的變更: 新增了 encodingerrors 參數。

在 3.14 版之後被棄用.

引數群組

預設情況下,ArgumentParser 在顯示說明訊息時會將命令列引數分成「位置引數」和「選項」兩組。當引數有比此預設分組更好的概念性分組時,可以使用 add_argument_group() 方法建立適當的群組:

>>> parser = argparse.ArgumentParser(prog='PROG', add_help=False)
>>> group = parser.add_argument_group('group')
>>> group.add_argument('--foo', help='foo help')
>>> group.add_argument('bar', help='bar help')
>>> parser.print_help()
usage: PROG [--foo FOO] bar

group:
  bar    bar help
  --foo FOO  foo help

add_argument_group() 方法回傳一個引數群組物件,它具有與一般 ArgumentParser 相同的 add_argument() 方法。當引數被加入群組時,剖析器會像處理正常引數一樣處理它,但在說明訊息中以獨立的群組顯示該引數。add_argument_group() 方法接受 titledescription 引數,可以用來自訂此顯示:

>>> parser = argparse.ArgumentParser(prog='PROG', add_help=False)
>>> group1 = parser.add_argument_group('group1', 'group1 description')
>>> group1.add_argument('foo', help='foo help')
>>> group2 = parser.add_argument_group('group2', 'group2 description')
>>> group2.add_argument('--bar', help='bar help')
>>> parser.print_help()
usage: PROG [--bar BAR] foo

group1:
  group1 description

  foo    foo help

group2:
  group2 description

  --bar BAR  bar help

選擇性的僅限關鍵字參數 argument_defaultconflict_handler 允許對引數群組的行為進行更精細的控制。這些參數的意義與 ArgumentParser 建構函式中的相同,但專門適用於引數群組而非整個剖析器。

請注意,任何不在使用者定義群組中的引數會歸入一般的「位置引數」和「可選引數」區段。

Within each argument group, arguments are displayed in help output in the order in which they are added.

自從版本 3.11 後不推薦使用,已從版本 3.14 中移除。: 在引數群組上呼叫 add_argument_group() 現在會引發例外。這種巢狀用法從未被支援,通常無法正確運作,是因為繼承而無意間被公開出來的。

在 3.14 版之後被棄用: prefix_chars 傳給 add_argument_group() 的用法現在已棄用。

互斥

建立一個互斥群組。argparse 會確保互斥群組中只有一個引數出現在命令列上:

>>> parser = argparse.ArgumentParser(prog='PROG')
>>> group = parser.add_mutually_exclusive_group()
>>> group.add_argument('--foo', action='store_true')
>>> group.add_argument('--bar', action='store_false')
>>> parser.parse_args(['--foo'])
Namespace(bar=True, foo=True)
>>> parser.parse_args(['--bar'])
Namespace(bar=False, foo=False)
>>> parser.parse_args(['--foo', '--bar'])
usage: PROG [-h] [--foo | --bar]
PROG: error: argument --bar: not allowed with argument --foo

add_mutually_exclusive_group() 方法也接受一個 required 引數,用來指示至少需要一個互斥引數:

>>> parser = argparse.ArgumentParser(prog='PROG')
>>> group = parser.add_mutually_exclusive_group(required=True)
>>> group.add_argument('--foo', action='store_true')
>>> group.add_argument('--bar', action='store_false')
>>> parser.parse_args([])
usage: PROG [-h] (--foo | --bar)
PROG: error: one of the arguments --foo --bar is required

請注意,目前互斥引數群組不支援 add_argument_group()titledescription 引數。然而互斥群組可以加入到具有標題和描述的引數群組中。例如:

>>> parser = argparse.ArgumentParser(prog='PROG')
>>> group = parser.add_argument_group('Group title', 'Group description')
>>> exclusive_group = group.add_mutually_exclusive_group(required=True)
>>> exclusive_group.add_argument('--foo', help='foo help')
>>> exclusive_group.add_argument('--bar', help='bar help')
>>> parser.print_help()
usage: PROG [-h] (--foo FOO | --bar BAR)

options:
  -h, --help  show this help message and exit

Group title:
  Group description

  --foo FOO   foo help
  --bar BAR   bar help

自從版本 3.11 後不推薦使用,已從版本 3.14 中移除。: 在互斥群組上呼叫 add_argument_group()add_mutually_exclusive_group() 現在會引發例外。這種巢狀用法從未支援,通常無法正確運作,且是因為繼承而無意間被公開出來的。

剖析器預設值

ArgumentParser.set_defaults(**kwargs)

在大多數情況下,parse_args() 回傳物件的屬性會完全由檢查命令列引數和引數 action 來決定。set_defaults() 允許加入一些無需檢查命令列即可決定的額外屬性:

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('foo', type=int)
>>> parser.set_defaults(bar=42, baz='badger')
>>> parser.parse_args(['736'])
Namespace(bar=42, baz='badger', foo=736)

請注意,預設值可以在剖析器層級使用 set_defaults() 設定,也可以在引數層級使用 add_argument() 設定。如果兩者都為同一個引數呼叫,會使用最後設定的預設值:

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', default='bar')
>>> parser.set_defaults(foo='spam')
>>> parser.parse_args([])
Namespace(foo='spam')

在使用多個剖析器時,剖析器層級的預設值可能特別有用。請參閱 add_subparsers() 方法以了解這類範例。

ArgumentParser.get_default(dest)

取得命名空間屬性的預設值,由 add_argument()set_defaults() 設定:

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', default='badger')
>>> parser.get_default('foo')
'badger'

印出幫助訊息

在大多數典型的應用程式中,parse_args() 會處理格式化和印出任何用法或錯誤訊息。然而,有幾個格式化方法可以使用:

ArgumentParser.print_usage(file=None)

印出 ArgumentParser 在命令列上呼叫方式的簡短描述。如果 fileNone,則假設為 sys.stdout

ArgumentParser.print_help(file=None)

印出說明訊息,包括程式用法和在 ArgumentParser 中註冊的引數相關資訊。如果 fileNone,假設為 sys.stdout

這些方法也有變體,它們只回傳字串而非印出它:

ArgumentParser.format_usage()

回傳一個字串,包含 ArgumentParser 在命令列上的呼叫方式的簡短描述。

ArgumentParser.format_help()

回傳一個字串,包含說明訊息,包括程式用法和在 ArgumentParser 中註冊的引數相關資訊。

部分剖析

ArgumentParser.parse_known_args(args=None, namespace=None)

有時候一個腳本只需要處理特定的一組命令列引數,將任何未辨識的引數留給另一個腳本或程式。在這些情況下,parse_known_args() 方法可能很有用。

此方法的運作方式類似 parse_args(),但它不會對額外的、未辨識的引數引發錯誤,而是會只剖析已知的引數並回傳一個包含填充後的命名空間和任何未辨識引數串列的二元素元組。

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', action='store_true')
>>> parser.add_argument('bar')
>>> parser.parse_known_args(['--foo', '--badger', 'BAR', 'spam'])
(Namespace(bar='BAR', foo=True), ['--badger', 'spam'])

警告

前綴匹配規則適用於 parse_known_args()。即使選項只是其已知選項之一的前綴,剖析器也可能消耗它,而非將其留在剩餘引數串列中。

自訂檔案剖析

ArgumentParser.convert_arg_line_to_args(arg_line)

從檔案讀取的引數(請參閱 ArgumentParser 建構函式的 fromfile_prefix_chars 關鍵字引數)每行讀取一個引數。可以覆寫 convert_arg_line_to_args() 以進行更精細的讀取。

此方法接受單個引數 arg_line,它是從引數檔案讀取的字串。它回傳從此字串剖析出的引數串列。此方法對從引數檔案讀取的每一行依序呼叫一次。

此方法的一個有用覆寫是將每個以空格分隔的詞作為引數。以下範例示範了如何做到這一點:

class MyArgumentParser(argparse.ArgumentParser):
    def convert_arg_line_to_args(self, arg_line):
        return arg_line.split()

Note that with this override an argument can no longer contain spaces, since each space-separated word becomes a separate argument.

退出方法

ArgumentParser.exit(status=0, message=None)

此方法終止程式,以指定的 status 退出,並在退出前(如果有提供的話)向 sys.stderr 印出一個 message。使用者可以覆寫此方法來以不同方式處理這些步驟:

class ErrorCatchingArgumentParser(argparse.ArgumentParser):
    def exit(self, status=0, message=None):
        if status:
            raise Exception(f'Exiting because of an error: {message}')
        exit(status)
ArgumentParser.error(message)

此方法將用法訊息(包含 message)印出到 sys.stderr,並以狀態碼 2 終止程式。

交錯剖析

ArgumentParser.parse_intermixed_args(args=None, namespace=None)
ArgumentParser.parse_known_intermixed_args(args=None, namespace=None)

許多 Unix 命令允許使用者將可選引數與位置引數交錯使用。parse_intermixed_args()parse_known_intermixed_args() 方法支援此剖析風格。

這些剖析器不支援所有 argparse 功能,如果使用了不支援的功能會引發例外。特別是不支援子剖析器,以及同時包含可選引數和位置引數的互斥群組。

以下範例展示了 parse_known_args()parse_intermixed_args() 之間的差異:前者回傳 ['2', '3'] 作為未剖析的引數,而後者將所有位置引數收集到 rest 中。

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo')
>>> parser.add_argument('cmd')
>>> parser.add_argument('rest', nargs='*', type=int)
>>> parser.parse_known_args('doit 1 --foo bar 2 3'.split())
(Namespace(cmd='doit', foo='bar', rest=[1]), ['2', '3'])
>>> parser.parse_intermixed_args('doit 1 --foo bar 2 3'.split())
Namespace(cmd='doit', foo='bar', rest=[1, 2, 3])

parse_known_intermixed_args() 回傳一個二元素元組,包含填充後的命名空間和剩餘引數字串的串列。parse_intermixed_args() 在有任何剩餘未剖析的引數字串時會引發錯誤。

在 3.7 版被加入.

註冊自訂型別或 action

ArgumentParser.register(registry_name, value, object)

有時候想要在錯誤訊息中使用自訂字串以提供更友善的輸出。在這些情況下,可以使用 register() 向剖析器註冊自訂 action 或型別,讓你可以透過註冊名稱而非可呼叫物件名稱來參照型別。

register() 方法接受三個引數——registry_name,指定用於儲存物件的內部登錄檔(例如 actiontype);value,用於註冊物件的鍵值;以及 object,要註冊的可呼叫物件。

以下範例展示如何向剖析器註冊自訂型別:

>>> import argparse
>>> parser = argparse.ArgumentParser()
>>> parser.register('type', 'hexadecimal integer', lambda s: int(s, 16))
>>> parser.add_argument('--foo', type='hexadecimal integer')
_StoreAction(option_strings=['--foo'], dest='foo', nargs=None, const=None, default=None, type='hexadecimal integer', choices=None, required=False, help=None, metavar=None, deprecated=False)
>>> parser.parse_args(['--foo', '0xFA'])
Namespace(foo=250)
>>> parser.parse_args(['--foo', '1.2'])
usage: PROG [-h] [--foo FOO]
PROG: error: argument --foo: invalid 'hexadecimal integer' value: '1.2'

例外

exception argparse.ArgumentError

建立或使用引數(可選或位置引數)時的錯誤。

此例外的字串值是訊息,附帶了導致錯誤的引數的相關資訊。

exception argparse.ArgumentTypeError

當將命令列字串轉換為型別時出錯時引發。

指南與教學