Argparse 教學¶
- 作者:
Tshepang Mbambo
本教學旨在簡要介紹 argparse 這個 Python 標準函式庫中推薦的命令列剖析模組。
備註
標準函式庫包含另外兩個與命令列參數處理直接相關的函式庫:較低階的 optparse 模組(可能需要更多程式碼來為給定應用程式設定,但也允許應用程式要求 argparse 不支援的行為),以及非常低階的 getopt(專門用作 C 程式設計師可用的 getopt() 函式系列的等價)。雖然這個指南並未直接涵蓋這些模組,但 argparse 的許多核心概念最初來自於 optparse,因此本教學的某些部分也適用於 optparse 使用者。
概念¶
讓我們透過使用 ls 指令來展示我們將在本介紹教學中探索的功能類型:
$ ls
cpython devguide prog.py pypy rm-unused-function.patch
$ ls pypy
ctypes_configure demo dotviewer include lib_pypy lib-python ...
$ ls -l
total 20
drwxr-xr-x 19 wena wena 4096 Feb 18 18:51 cpython
drwxr-xr-x 4 wena wena 4096 Feb 8 12:04 devguide
-rwxr-xr-x 1 wena wena 535 Feb 19 00:05 prog.py
drwxr-xr-x 14 wena wena 4096 Feb 7 00:59 pypy
-rw-r--r-- 1 wena wena 741 Feb 18 01:01 rm-unused-function.patch
$ ls --help
Usage: ls [OPTION]... [FILE]...
List information about the FILEs (the current directory by default).
Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.
...
我們可以從這四個命令中學到一些概念:
ls 命令即便在沒有任何選項的情況下執行仍非常有用。它預設顯示目前目錄的內容。
如果我們想要看到比它預設提供更多的內容,我們也需要多告訴它一點。在本例中,我們希望它顯示不同的目錄
pypy,我們做的是指定所謂的位置引數。之所以如此命名是因為程式應該只根據該值在命令列中出現的位置來知道如何處理該值。這個概念與 cp 這樣的指令更相關,其最基本的用法是cp SRC DEST。第一個是你想要複製的位置,第二個是你想要複製過去的位置。現在假設我們想要改變程式的行為。在我們的範例中,我們顯示每個檔案的更多資訊,而不僅是顯示檔案名稱。在這種情況下,
-l被稱為可選引數。這是幫助文字的片段。它非常有用,因為當你遇到以前從未使用過的程式時,只需閱讀其幫助文字即可了解它的工作原理。
基本用法¶
讓我們從一個非常簡單的例子開始,它(幾乎)什麼都不做:
import argparse
parser = argparse.ArgumentParser()
parser.parse_args()
程式碼執行結果如下:
$ python prog.py
$ python prog.py --help
usage: prog.py [-h]
options:
-h, --help show this help message and exit
$ python prog.py --verbose
usage: prog.py [-h]
prog.py: error: unrecognized arguments: --verbose
$ python prog.py foo
usage: prog.py [-h]
prog.py: error: unrecognized arguments: foo
這是發生的事情:
執行不帶任何選項的腳本不會在標準輸出中顯示任何內容。不太有用。
第二個開始能夠顯現
argparse模組的有用之處。我們幾乎什麼也沒做,但我們已經收到了一個很好的幫助訊息。--help選項也可以縮寫為-h,是我們能隨意獲得的唯一選項(即無需指定它)。指定任何其他內容都會導致錯誤。但即便如此,我們也還是輕鬆地獲得了有用的使用資訊。
位置引數的介紹¶
例如:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("echo")
args = parser.parse_args()
print(args.echo)
執行這段程式碼:
$ python prog.py
usage: prog.py [-h] echo
prog.py: error: the following arguments are required: echo
$ python prog.py --help
usage: prog.py [-h] echo
positional arguments:
echo
options:
-h, --help show this help message and exit
$ python prog.py foo
foo
這是會發生的事情:
我們新增了
add_argument()方法,我們用它來指定程式願意接受哪些命令列選項。在本例中,我將其命名為echo,以便與其功能一致。現在呼叫我們的程式時需要指定一個選項。
parse_args()方法實際上從指定的選項中回傳一些資料,在本例中為echo。該變數是某種形式的「魔法」,
argparse可以自由執行(即無需指定該值儲存在哪個變數中)。你還會注意到,它的名稱與提供給方法echo的字串引數相符。
但請注意,儘管幫助顯示看起來不錯,但它目前還沒有發揮出應有的用處。例如,我們看到 echo 作為位置引數,但除了猜測或閱讀原始程式碼之外,我們不知道它的作用。那麼,我們來讓它變得更有用一點:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("echo", help="echo the string you use here")
args = parser.parse_args()
print(args.echo)
然後我們得到:
$ python prog.py -h
usage: prog.py [-h] echo
positional arguments:
echo echo the string you use here
options:
-h, --help show this help message and exit
現在來做一些更有用處的事情:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", help="display a square of a given number")
args = parser.parse_args()
print(args.square**2)
程式碼執行結果如下:
$ python prog.py 4
Traceback (most recent call last):
File "prog.py", line 5, in <module>
print(args.square**2)
TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
進展不太順利。這是因為,除非我們另有說明,argparse 會將我們給它的選項視為字串。因此,讓我們告訴 argparse 將該輸入視為整數:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", help="display a square of a given number",
type=int)
args = parser.parse_args()
print(args.square**2)
程式碼執行結果如下:
$ python prog.py 4
16
$ python prog.py four
usage: prog.py [-h] square
prog.py: error: argument square: invalid int value: 'four'
順利進展。現在該程式甚至可以在繼續操作之前因錯誤的非法輸入而退出。
可選引數的介紹¶
到目前為止,我們一直在討論位置引數。我們來看看如何新增可選引數:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--verbosity", help="increase output verbosity")
args = parser.parse_args()
if args.verbosity:
print("verbosity turned on")
接者是結果:
$ python prog.py --verbosity 1
verbosity turned on
$ python prog.py
$ python prog.py --help
usage: prog.py [-h] [--verbosity VERBOSITY]
options:
-h, --help show this help message and exit
--verbosity VERBOSITY
increase output verbosity
$ python prog.py --verbosity
usage: prog.py [-h] [--verbosity VERBOSITY]
prog.py: error: argument --verbosity: expected one argument
這是發生的事情:
程式被編寫為在指定
--verbosity時顯示一些內容,並在未指定時不顯示任何內容。為了表示該選項實際上是可選的,沒使用它來執行程式並不會出現錯誤。請注意,預設情況下,如果未使用可選引數,則相關變數(在本例中為
args.verbosity)將被賦予None作為值,這就是它未能通過if陳述式真值測試的原因。幫助訊息有點不同。
當使用
--verbosity選項時必須要指定一些值,任何值都可以。
在上面的例子中,--verbosity 接受任意的整數,但對我們的程式來說只接受兩個輸入值, True 或 False。所以我們來修改一下程式碼使其符合:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--verbose", help="increase output verbosity",
action="store_true")
args = parser.parse_args()
if args.verbose:
print("verbosity turned on")
接者是結果:
$ python prog.py --verbose
verbosity turned on
$ python prog.py --verbose 1
usage: prog.py [-h] [--verbose]
prog.py: error: unrecognized arguments: 1
$ python prog.py --help
usage: prog.py [-h] [--verbose]
options:
-h, --help show this help message and exit
--verbose increase output verbosity
這是發生的事情:
這個選項現在更像是一個旗標,而不是需要值的東西。我們甚至更改了選項的名稱以符合這個想法。請注意,我們現在指定一個新的關鍵字
action,並為其指定值"store_true"。這意味著,如果指定了該選項,則將值True指派給args.verbose。不指定它代表為False。當你指定一個值時,它會本著旗標的實際精神來抱怨。
請注意不同的幫助文字。
短選項¶
如果你熟悉命令列用法,你會注意到我尚未提及選項的簡短版本。這很簡單:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-v", "--verbose", help="increase output verbosity",
action="store_true")
args = parser.parse_args()
if args.verbose:
print("verbosity turned on")
而這為:
$ python prog.py -v
verbosity turned on
$ python prog.py --help
usage: prog.py [-h] [-v]
options:
-h, --help show this help message and exit
-v, --verbose increase output verbosity
請注意,新功能也反映在幫助文字中。
組合位置引數和可選引數¶
我們的程式的複雜性不斷增加:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
help="display a square of a given number")
parser.add_argument("-v", "--verbose", action="store_true",
help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
if args.verbose:
print(f"the square of {args.square} equals {answer}")
else:
print(answer)
然後現在的輸出結果:
$ python prog.py
usage: prog.py [-h] [-v] square
prog.py: error: the following arguments are required: square
$ python prog.py 4
16
$ python prog.py 4 --verbose
the square of 4 equals 16
$ python prog.py --verbose 4
the square of 4 equals 16
我們帶回了位置引數,因而被抱怨。
請注意,順序並不重要。
我們讓這個程式擁有多個訊息詳細級別 (verbosity) 之值的能力,並實際使用它們:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
help="display a square of a given number")
parser.add_argument("-v", "--verbosity", type=int,
help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
if args.verbosity == 2:
print(f"the square of {args.square} equals {answer}")
elif args.verbosity == 1:
print(f"{args.square}^2 == {answer}")
else:
print(answer)
接者是結果:
$ python prog.py 4
16
$ python prog.py 4 -v
usage: prog.py [-h] [-v VERBOSITY] square
prog.py: error: argument -v/--verbosity: expected one argument
$ python prog.py 4 -v 1
4^2 == 16
$ python prog.py 4 -v 2
the square of 4 equals 16
$ python prog.py 4 -v 3
16
除了最後一個外都看起來正常,它透露了我們程式中的一個錯誤。我們可透過限制 --verbosity 選項可以接受的值來修復它:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
help="display a square of a given number")
parser.add_argument("-v", "--verbosity", type=int, choices=[0, 1, 2],
help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
if args.verbosity == 2:
print(f"the square of {args.square} equals {answer}")
elif args.verbosity == 1:
print(f"{args.square}^2 == {answer}")
else