optparse — 命令列選項解析器

原始碼: Lib/optparse.py


選擇一個引數解析庫

標準庫包含三個引數解析庫

  • getopt:一個模組,緊密地反映了過程式 C getopt API。自初始 Python 1.0 版本釋出之前就已包含在標準庫中。

  • optparsegetopt 的宣告式替代方案,提供等效的功能,而無需每個應用程式實現自己的過程式選項解析邏輯。自 Python 2.3 版本起包含在標準庫中。

  • argparse:一個比 optparse 更具主觀性的替代方案,預設情況下提供更多功能,但代價是降低了應用程式在精確控制引數處理方式方面的靈活性。自 Python 2.7 和 Python 3.2 版本起包含在標準庫中。

在沒有更具體的引數解析設計約束的情況下,argparse 是實現命令列應用程式的推薦選擇,因為它以最少的應用程式級別程式碼提供了最高級別的基線功能。

getopt 幾乎完全出於向後相容的原因而保留。但是,它也作為在基於 getopt 的 C 應用程式中原型設計和測試命令列引數處理的工具,服務於一個小眾用例。

optparse 在以下情況下應被視為 argparse 的替代方案

  • 應用程式已在使用 optparse,並且不想冒險遷移到 argparse 時可能出現的細微行為變化

  • 應用程式需要對命令列上選項和位置引數的交錯方式進行額外的控制(包括完全停用交錯功能的能力)

  • 應用程式需要對命令列元素的增量解析進行額外的控制(雖然 argparse 支援此功能,但它在實踐中的確切工作方式對於某些用例來說是不希望的)

  • 應用程式需要對接受可能以 - 開頭的引數值的選項的處理進行額外的控制(例如要傳遞給呼叫的子程序的委派選項)

  • 應用程式需要一些 argparse 不支援的其他命令列引數處理行為,但可以使用 optparse 提供的較低級別介面來實現

這些考慮因素還意味著,對於編寫第三方命令列引數處理庫的庫作者來說,optparse 可能提供更好的基礎。

作為一個具體的例子,請考慮以下兩種命令列引數解析配置,第一種使用 optparse,第二種使用 argparse

import optparse

if __name__ == '__main__':
    parser = optparse.OptionParser()
    parser.add_option('-o', '--output')
    parser.add_option('-v', dest='verbose', action='store_true')
    opts, args = parser.parse_args()
    process(args, output=opts.output, verbose=opts.verbose)
import argparse

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('-o', '--output')
    parser.add_argument('-v', dest='verbose', action='store_true')
    parser.add_argument('rest', nargs='*')
    args = parser.parse_args()
    process(args.rest, output=args.output, verbose=args.verbose)

最明顯的區別是,在 optparse 版本中,非選項引數在選項處理完成後由應用程式單獨處理。在 argparse 版本中,位置引數的宣告和處理方式與命名選項相同。

但是,argparse 版本還會以不同於 optparse 版本處理某些引數組合的方式來處理它們。例如(除其他差異外)

  • 提供 -o -v 在使用 optparse 時會給出 output="-v"verbose=False,但在使用 argparse 時會給出用法錯誤(抱怨沒有為 -o/--output 提供值,因為 -v 被解釋為表示詳細標誌)

  • 同樣,提供 -o -- 在使用 optparse 時會給出 output="--"args=(),但在使用 argparse 時會給出用法錯誤(也抱怨沒有為 -o/--output 提供值,因為 -- 被解釋為終止選項處理並將所有剩餘值視為位置引數)

  • 當使用 optparse 時,提供 -o=foo 會得到 output="=foo",而使用 argparse 則會得到 output="foo"(因為 = 被特殊處理為選項引數值的替代分隔符)。

argparse 版本中,這些不同的行為是否被認為是期望的或問題,將取決於具體的命令列應用程式用例。

另請參閱

click 是一個第三方引數處理庫(最初基於 optparse),它允許將命令列應用程式開發為一組裝飾的命令實現函式。

其他第三方庫,例如 typermsgspec-click,允許以更有效地與 Python 型別註解的靜態檢查整合的方式指定命令列介面。

簡介

optparse 是一個比極簡的 getopt 模組更方便、更靈活和更強大的命令列選項解析庫。optparse 使用一種更具宣告式的命令列解析風格:您建立一個 OptionParser 的例項,用選項填充它,並解析命令列。optparse 允許使用者以傳統的 GNU/POSIX 語法指定選項,併為您生成用法和幫助訊息。

這是一個在簡單指令碼中使用 optparse 的示例

from optparse import OptionParser
...
parser = OptionParser()
parser.add_option("-f", "--file", dest="filename",
                  help="write report to FILE", metavar="FILE")
parser.add_option("-q", "--quiet",
                  action="store_false", dest="verbose", default=True,
                  help="don't print status messages to stdout")

(options, args) = parser.parse_args()

使用這幾行程式碼,您的指令碼使用者現在可以在命令列上執行“通常的操作”,例如

<yourscript> --file=outfile -q

當解析命令列時,optparse 根據使用者提供的命令列值設定由 parse_args() 返回的 options 物件的屬性。當 parse_args() 從解析此命令列返回時,options.filename 將為 "outfile",而 options.verbose 將為 Falseoptparse 支援長選項和短選項,允許將短選項合併在一起,並允許以多種方式將選項與其引數關聯。因此,以下命令列都等效於上述示例

<yourscript> -f outfile --quiet
<yourscript> --quiet --file outfile
<yourscript> -q -foutfile
<yourscript> -qfoutfile

此外,使用者可以執行以下命令之一

<yourscript> -h
<yourscript> --help

optparse 將打印出您的指令碼選項的簡要摘要

Usage: <yourscript> [options]

Options:
  -h, --help            show this help message and exit
  -f FILE, --file=FILE  write report to FILE
  -q, --quiet           don't print status messages to stdout

其中 yourscript 的值在執行時確定(通常來自 sys.argv[0])。

背景

optparse 被明確設計為鼓勵建立具有簡單命令列介面的程式,這些介面遵循 C 開發人員可用的 getopt() 系列函式建立的約定。為此,它僅支援 Unix 下常用的最常見的命令列語法和語義。如果您不熟悉這些約定,閱讀本節將使您熟悉它們。

術語

引數

在命令列中輸入的字串,由 shell 傳遞給 execl()execv()。在 Python 中,引數是 sys.argv[1:] 的元素(sys.argv[0] 是正在執行的程式的名稱)。Unix shell 也使用術語“詞”。

有時需要替換 sys.argv[1:] 以外的引數列表,因此您應該將“引數”理解為“sys.argv[1:] 的元素,或作為 sys.argv[1:] 的替代提供的其他列表的元素”。

選項

用於提供額外資訊以指導或自定義程式執行的引數。選項有許多不同的語法;傳統的 Unix 語法是一個連字元(“-”)後跟一個字母,例如 -x-F。此外,傳統的 Unix 語法允許將多個選項合併為單個引數,例如 -x -F 等效於 -xF。GNU 專案引入了 -- 後跟一系列連字元分隔的單詞,例如 --file--dry-run。這些是 optparse 提供的僅有的兩種選項語法。

世界上出現的一些其他選項語法包括

  • 一個連字元後跟幾個字母,例如 -pf(這與合併為單個引數的多個選項相同)

  • 一個連字元後跟一個完整的單詞,例如 -file(這在技術上等效於前一種語法,但它們通常不會在同一程式中看到)

  • 一個加號後跟一個字母、幾個字母或一個單詞,例如 +f, +rgb

  • 一個斜槓後跟一個字母、幾個字母或一個單詞,例如 /f, /file

這些選項語法不受 optparse 支援,並且永遠不會支援。這是故意的:前三個在任何環境下都是非標準的,而最後一個只有當您專門針對 Windows 或某些舊平臺(例如 VMS、MS-DOS)時才有意義。

選項引數

一個跟隨選項的引數,與該選項緊密相關,並在該選項出現時從引數列表中消耗掉。使用 optparse,選項引數可能與其選項在單獨的引數中

-f foo
--file foo

或包含在同一引數中

-ffoo
--file=foo

通常,給定的選項要麼接受一個引數,要麼不接受。很多人想要“可選選項引數”功能,這意味著一些選項如果看到它就會接受一個引數,如果看不到就不會接受。這有點爭議,因為它使解析模糊不清:如果 -a 接受一個可選引數,而 -b 是另一個完全不同的選項,我們如何解釋 -ab?由於這種模糊性,optparse 不支援此功能。

位置引數

在解析選項後,即在解析選項及其引數並從引數列表中刪除後,引數列表中剩餘的內容。

必需選項

必須在命令列上提供的選項;請注意,“必需選項”一詞在英語中是自相矛盾的。optparse 不會阻止您實現必需選項,但也不會對此提供太多幫助。

例如,考慮以下假設的命令列

prog -v --report report.txt foo bar

-v--report 都是選項。假設 --report 接受一個引數,則 report.txt 是一個選項引數。foobar 是位置引數。

選項的用途是什麼?

選項用於提供額外資訊來調整或自定義程式的執行。以防萬一不清楚,選項通常是可選的。程式應該能夠在沒有任何選項的情況下正常執行。(從 Unix 或 GNU 工具集中選擇一個隨機程式。它可以在沒有任何選項的情況下執行並仍然有意義嗎?主要的例外是 findtardd,所有這些都是因其非標準語法和令人困惑的介面而受到批評的變異怪胎。)

很多人希望他們的程式具有“必需選項”。想一想。如果它是必需的,那麼它就不是可選的!如果您的程式絕對需要某些資訊才能成功執行,那麼這就是位置引數的用途。

作為良好命令列介面設計的一個示例,請考慮用於複製檔案的簡單 cp 實用程式。嘗試在不提供目標和至少一個源的情況下複製檔案沒有多大意義。因此,如果您在沒有引數的情況下執行 cp,它會失敗。但是,它具有靈活、有用的語法,根本不需要任何選項

cp SOURCE DEST
cp SOURCE ... DEST-DIR

僅僅使用這些,你就可以走得很遠。大多數 cp 實現都提供了一系列選項來精確調整檔案的複製方式:你可以保留模式和修改時間,避免跟隨符號連結,在覆蓋現有檔案之前詢問等等。但是,所有這些都不會分散 cp 的核心任務,即將一個檔案複製到另一個檔案,或者將多個檔案複製到另一個目錄。

位置引數是用來做什麼的?

位置引數用於那些你的程式絕對、明確需要執行的資訊。

一個好的使用者介面應該儘可能減少絕對要求。如果你的程式需要 17 個不同的資訊才能成功執行,那麼如何從使用者那裡獲取這些資訊並不重要——大多數人會在成功執行程式之前放棄並走開。這適用於使用者介面是命令列、配置檔案還是 GUI:如果你對使用者提出如此多的要求,他們中的大多數人會直接放棄。

簡而言之,儘量減少使用者絕對需要提供的資訊量——儘可能使用合理的預設值。當然,你也希望你的程式具有合理的靈活性。這就是選項的用途。同樣,它們是配置檔案中的條目、GUI “首選項” 對話方塊中的小部件,還是命令列選項並不重要——你實現的選項越多,你的程式就越靈活,其實現就越複雜。當然,過多的靈活性也有缺點;太多的選項可能會讓使用者感到不知所措,並使你的程式碼更難維護。

教程

雖然 optparse 非常靈活且功能強大,但在大多數情況下使用也很簡單。本節介紹任何基於 optparse 的程式中常見的程式碼模式。

首先,你需要匯入 OptionParser 類;然後,在主程式的早期,建立一個 OptionParser 例項

from optparse import OptionParser
...
parser = OptionParser()

然後你可以開始定義選項。基本語法是

parser.add_option(opt_str, ...,
                  attr=value, ...)

每個選項都有一個或多個選項字串,例如 -f--file,以及幾個選項屬性,這些屬性告訴 optparse 在命令列上遇到該選項時應該期待什麼以及應該做什麼。

通常,每個選項都會有一個短選項字串和一個長選項字串,例如

parser.add_option("-f", "--file", ...)

你可以自由定義任意數量的短選項字串和任意數量的長選項字串(包括零),只要總體上至少有一個選項字串即可。

傳遞給 OptionParser.add_option() 的選項字串實際上是由該呼叫定義的選項的標籤。為簡潔起見,我們將經常提到在命令列上遇到一個選項;實際上,optparse 遇到的是選項字串,並從中查詢選項。

定義完所有選項後,指示 optparse 解析程式的命令列

(options, args) = parser.parse_args()

(如果你願意,可以將自定義引數列表傳遞給 parse_args(),但這很少是必要的:預設情況下它使用 sys.argv[1:]。)

parse_args() 返回兩個值

  • options,一個包含所有選項值的物件——例如,如果 --file 接受一個字串引數,那麼 options.file 將是使用者提供的檔名,如果使用者沒有提供該選項,則為 None

  • args,解析選項後剩餘的位置引數列表

本教程部分僅涵蓋四個最重要的選項屬性:actiontypedest(目標)和 help。其中,action 是最基本的。

理解選項動作

動作告訴 optparse 當它在命令列上遇到一個選項時應該做什麼。optparse 中硬編碼了一組固定的動作;新增新動作是 擴充套件 optparse 部分中涵蓋的高階主題。大多數動作告訴 optparse 將一個值儲存到某個變數中——例如,從命令列獲取一個字串並將其儲存為 options 的屬性。

如果你沒有指定選項動作,optparse 預設為 store

store 動作

最常見的選項動作是 store,它告訴 optparse 獲取下一個引數(或當前引數的剩餘部分),確保其型別正確,並將其儲存到你選擇的目標。

例如

parser.add_option("-f", "--file",
                  action="store", type="string", dest="filename")

現在讓我們編造一個假的命令列,並要求 optparse 解析它

args = ["-f", "foo.txt"]
(options, args) = parser.parse_args(args)

optparse 看到選項字串 -f 時,它會消耗下一個引數 foo.txt,並將其儲存在 options.filename 中。因此,在呼叫 parse_args() 後,options.filename"foo.txt"

optparse 支援的其他一些選項型別是 intfloat。這是一個期望整數引數的選項

parser.add_option("-n", type="int", dest="num")

請注意,此選項沒有長選項字串,這是完全可以接受的。此外,沒有顯式動作,因為預設值為 store

讓我們解析另一個假的命令列。這一次,我們將選項引數緊貼選項:因為 -n42(一個引數)等效於 -n 42(兩個引數),所以程式碼

(options, args) = parser.parse_args(["-n42"])
print(options.num)

將列印 42

如果你沒有指定型別,optparse 假設為 string。結合預設動作是 store 這一事實,這意味著我們的第一個示例可以更短

parser.add_option("-f", "--file", dest="filename")

如果你不提供目標(destination),optparse 會根據選項字串推斷出一個合理的預設值:如果第一個長選項字串是 --foo-bar,那麼預設目標是 foo_bar。如果沒有長選項字串,optparse 會檢視第一個短選項字串:-f 的預設目標是 f

optparse 還包括內建的 complex 型別。新增型別將在 擴充套件 optparse 部分介紹。

處理布林(標誌)選項

標誌選項——當看到特定選項時,將變數設定為 true 或 false——非常常見。optparse 透過兩個不同的動作支援它們,store_truestore_false。例如,你可能有一個 verbose 標誌,可以使用 -v 開啟,使用 -q 關閉。

parser.add_option("-v", action="store_true", dest="verbose")
parser.add_option("-q", action="store_false", dest="verbose")

這裡我們有兩個具有相同目標的不同選項,這完全沒問題。(這只是意味著你在設定預設值時需要小心一點——見下文。)

optparse 在命令列中遇到 -v 時,它會將 options.verbose 設定為 True;當它遇到 -q 時,options.verbose 被設定為 False

其他動作

optparse 支援的其他一些動作是

"store_const"

儲存一個常量值,透過 Option.const 預先設定

"append"

將此選項的引數附加到列表中

"count"

將計數器加一

"callback"

呼叫指定的函式

這些在 參考指南選項回撥 部分中介紹。

預設值

以上所有示例都涉及在看到某些命令列選項時設定某個變數(“目標”)。如果從未看到這些選項會發生什麼?由於我們沒有提供任何預設值,它們都被設定為 None。這通常沒問題,但有時你希望有更多的控制權。optparse 允許你為每個目標提供預設值,該預設值在解析命令列之前分配。

首先,考慮 verbose/quiet 示例。如果我們希望 optparseverbose 設定為 True,除非看到 -q,那麼我們可以這樣做

parser.add_option("-v", action="store_true", dest="verbose", default=True)
parser.add_option("-q", action="store_false", dest="verbose")

由於預設值應用於目標而不是任何特定選項,並且這兩個選項恰好具有相同的目標,這完全等效

parser.add_option("-v", action="store_true", dest="verbose")
parser.add_option("-q", action="store_false", dest="verbose", default=True)

考慮這個

parser.add_option("-v", action="store_true", dest="verbose", default=False)
parser.add_option("-q", action="store_false", dest="verbose", default=True)

同樣,verbose 的預設值將是 True:為任何特定目標提供的最後一個預設值是有效的。

指定預設值的更清晰的方法是 OptionParser 的 set_defaults() 方法,你可以在呼叫 parse_args() 之前的任何時間呼叫它。

parser.set_defaults(verbose=True)
parser.add_option(...)
(options, args) = parser.parse_args()

和以前一樣,為給定選專案標指定的最後一個值是有效的。為了清楚起見,請嘗試使用一種方法或另一種方法來設定預設值,而不是兩者都用。

生成幫助

optparse 自動生成幫助和用法文字的能力對於建立使用者友好的命令列介面非常有用。你所要做的就是為每個選項提供一個 help 值,以及可選的整個程式的簡短用法訊息。這是一個填充了使用者友好(已文件化)選項的 OptionParser

usage = "usage: %prog [options] arg1 arg2"
parser = OptionParser(usage=usage)
parser.add_option("-v", "--verbose",
                  action="store_true", dest="verbose", default=True,
                  help="make lots of noise [default]")
parser.add_option("-q", "--quiet",
                  action="store_false", dest="verbose",
                  help="be vewwy quiet (I'm hunting wabbits)")
parser.add_option("-f", "--filename",
                  metavar="FILE", help="write output to FILE")
parser.add_option("-m", "--mode",
                  default="intermediate",
                  help="interaction mode: novice, intermediate, "
                       "or expert [default: %default]")

如果 optparse 在命令列中遇到 -h--help,或者你只是呼叫 parser.print_help(),它會將以下內容列印到標準輸出

Usage: <yourscript> [options] arg1 arg2

Options:
  -h, --help            show this help message and exit
  -v, --verbose         make lots of noise [default]
  -q, --quiet           be vewwy quiet (I'm hunting wabbits)
  -f FILE, --filename=FILE
                        write output to FILE
  -m MODE, --mode=MODE  interaction mode: novice, intermediate, or
                        expert [default: intermediate]

(如果幫助輸出由幫助選項觸發,optparse 會在列印幫助文字後退出。)

這裡有很多內容可以幫助 optparse 生成最佳幫助訊息

  • 指令碼定義了自己的用法訊息

    usage = "usage: %prog [options] arg1 arg2"
    

    optparse 將用法字串中的 %prog 擴充套件為當前程式的名稱,即 os.path.basename(sys.argv[0])。然後,擴充套件的字串會在詳細的選項幫助之前列印。

    如果你不提供用法字串,optparse 會使用一個平淡但合理的預設值:"用法: %prog [選項]",如果你的指令碼不接受任何位置引數,這很好。

  • 每個選項都定義一個幫助字串,並且不用擔心換行——optparse 會負責換行並使幫助輸出看起來不錯。

  • 接受值的選項在其自動生成的幫助訊息中指示此事實,例如,對於“mode”選項

    -m MODE, --mode=MODE
    

    在這裡,“MODE”被稱為元變數:它代表使用者希望提供給 -m/--mode 的引數。預設情況下,optparse 將目標變數名轉換為大寫,並將其用作元變數。有時,這不是你想要的——例如,--filename 選項顯式設定 metavar="FILE",從而產生此自動生成的選項描述

    -f FILE, --filename=FILE
    

    但這不僅僅是為了節省空間:手動編寫的幫助文字使用元變數 FILE 來暗示使用者,在半正式語法 -f FILE 和非正式語義描述“將輸出寫入 FILE”之間存在聯絡。這是一種簡單但有效的方法,可以使你的幫助文字更清晰,對終端使用者更有用。

  • 具有預設值的選項可以在幫助字串中包含 %default——optparse 會將其替換為選項預設值的 str()。如果一個選項沒有預設值(或者預設值為 None),%default 會擴充套件為 none

選項分組

當處理許多選項時,將這些選項分組以便更好地輸出幫助資訊是很方便的。一個 OptionParser 可以包含多個選項組,每個選項組又可以包含多個選項。

可以使用 OptionGroup 類來獲取一個選項組。

class optparse.OptionGroup(parser, title, description=None)

其中:

  • parser 是要將該組插入的 OptionParser 例項。

  • title 是組的標題。

  • description(可選)是組的詳細描述。

OptionGroup 繼承自 OptionContainer(與 OptionParser 類似),因此可以使用 add_option() 方法向該組新增選項。

宣告完所有選項後,可以使用 OptionParser 的方法 add_option_group() 將該組新增到先前定義的解析器中。

繼續使用上一節中定義的解析器,將一個 OptionGroup 新增到解析器非常容易。

group = OptionGroup(parser, "Dangerous Options",
                    "Caution: use these options at your own risk.  "
                    "It is believed that some of them bite.")
group.add_option("-g", action="store_true", help="Group option.")
parser.add_option_group(group)

這將產生以下幫助輸出:

Usage: <yourscript> [options] arg1 arg2

Options:
  -h, --help            show this help message and exit
  -v, --verbose         make lots of noise [default]
  -q, --quiet           be vewwy quiet (I'm hunting wabbits)
  -f FILE, --filename=FILE
                        write output to FILE
  -m MODE, --mode=MODE  interaction mode: novice, intermediate, or
                        expert [default: intermediate]

  Dangerous Options:
    Caution: use these options at your own risk.  It is believed that some
    of them bite.

    -g                  Group option.

一個更完整的示例可能涉及使用多個組:仍然擴充套件前面的示例。

group = OptionGroup(parser, "Dangerous Options",
                    "Caution: use these options at your own risk.  "
                    "It is believed that some of them bite.")
group.add_option("-g", action="store_true", help="Group option.")
parser.add_option_group(group)

group = OptionGroup(parser, "Debug Options")
group.add_option("-d", "--debug", action="store_true",
                 help="Print debug information")
group.add_option("-s", "--sql", action="store_true",
                 help="Print all SQL statements executed")
group.add_option("-e", action="store_true", help="Print every action done")
parser.add_option_group(group)

這將產生以下輸出:

Usage: <yourscript> [options] arg1 arg2

Options:
  -h, --help            show this help message and exit
  -v, --verbose         make lots of noise [default]
  -q, --quiet           be vewwy quiet (I'm hunting wabbits)
  -f FILE, --filename=FILE
                        write output to FILE
  -m MODE, --mode=MODE  interaction mode: novice, intermediate, or expert
                        [default: intermediate]

  Dangerous Options:
    Caution: use these options at your own risk.  It is believed that some
    of them bite.

    -g                  Group option.

  Debug Options:
    -d, --debug         Print debug information
    -s, --sql           Print all SQL statements executed
    -e                  Print every action done

另一個有趣的方法,特別是在以程式設計方式處理選項組時,是:

OptionParser.get_option_group(opt_str)

返回短選項或長選項字串 *opt_str* (例如 '-o''--option') 所屬的 OptionGroup。如果沒有這樣的 OptionGroup,則返回 None

列印版本字串

與簡短的用法字串類似,optparse 也可以為您的程式列印版本字串。您必須將該字串作為 version 引數傳遞給 OptionParser。

parser = OptionParser(usage="%prog [-f] [-q]", version="%prog 1.0")

%prog 的展開方式與在 usage 中相同。除此之外,version 可以包含您喜歡的任何內容。當您提供它時,optparse 會自動向您的解析器新增一個 --version 選項。如果在命令列上遇到此選項,它將展開您的 version 字串(透過替換 %prog),將其列印到 stdout 並退出。

例如,如果您的指令碼名為 /usr/bin/foo

$ /usr/bin/foo --version
foo 1.0

可以使用以下兩個方法來列印和獲取 version 字串。

OptionParser.print_version(file=None)

將當前程式的版本訊息 (self.version) 列印到 *file* (預設為 stdout)。與 print_usage() 一樣,self.version 中任何出現的 %prog 都會被當前程式的名稱替換。如果 self.version 為空或未定義,則不執行任何操作。

OptionParser.get_version()

print_version() 相同,但返回版本字串而不是列印它。

optparse 如何處理錯誤

optparse 需要擔心兩種主要的錯誤型別:程式設計師錯誤和使用者錯誤。程式設計師錯誤通常是對 OptionParser.add_option() 的錯誤呼叫,例如無效的選項字串、未知的選項屬性、缺少的選項屬性等。這些錯誤通常以通常的方式處理:引發異常(optparse.OptionErrorTypeError),並讓程式崩潰。

處理使用者錯誤更為重要,因為無論您的程式碼多麼穩定,都保證會發生這些錯誤。optparse 可以自動檢測到一些使用者錯誤,例如錯誤的選項引數(傳遞 -n 4x,而 -n 需要一個整數引數)、缺少引數(命令列末尾的 -n,而 -n 需要任何型別的引數)。此外,您可以呼叫 OptionParser.error() 來發出應用程式定義的錯誤情況的訊號。

(options, args) = parser.parse_args()
...
if options.a and options.b:
    parser.error("options -a and -b are mutually exclusive")

在任何一種情況下,optparse 都會以相同的方式處理錯誤:它會將程式的用法訊息和錯誤訊息列印到標準錯誤,並以錯誤狀態 2 退出。

考慮上面的第一個示例,其中使用者向需要整數的選項傳遞了 4x

$ /usr/bin/foo -n 4x
Usage: foo [options]

foo: error: option -n: invalid integer value: '4x'

或者,使用者根本沒有傳遞值。

$ /usr/bin/foo -n
Usage: foo [options]

foo: error: -n option requires an argument

optparse 生成的錯誤訊息始終會提及錯誤中涉及的選項;當從您的應用程式程式碼中呼叫 OptionParser.error() 時,請確保執行相同的操作。

如果 optparse 的預設錯誤處理行為不適合您的需求,您需要對 OptionParser 進行子類化,並覆蓋其 exit() 和/或 error() 方法。

將它們放在一起

以下是基於 optparse 的指令碼通常的樣子。

from optparse import OptionParser
...
def main():
    usage = "usage: %prog [options] arg"
    parser = OptionParser(usage)
    parser.add_option("-f", "--file", dest="filename",
                      help="read data from FILENAME")
    parser.add_option("-v", "--verbose",
                      action="store_true", dest="verbose")
    parser.add_option("-q", "--quiet",
                      action="store_false", dest="verbose")
    ...
    (options, args) = parser.parse_args()
    if len(args) != 1:
        parser.error("incorrect number of arguments")
    if options.verbose:
        print("reading %s..." % options.filename)
    ...

if __name__ == "__main__":
    main()

參考指南

建立解析器

使用 optparse 的第一步是建立一個 OptionParser 例項。

class optparse.OptionParser(...)

OptionParser 建構函式沒有必需的引數,但有許多可選的關鍵字引數。您應該始終將它們作為關鍵字引數傳遞,即不要依賴於引數宣告的順序。

usage (預設: "%prog [options]")

當您的程式執行不正確或帶有 help 選項時要列印的用法摘要。當 optparse 列印用法字串時,它會將 %prog 展開為 os.path.basename(sys.argv[0])(如果傳遞了該關鍵字引數,則展開為 prog)。要禁止用法訊息,請傳遞特殊值 optparse.SUPPRESS_USAGE

option_list (預設: [])

用於填充解析器的 Option 物件列表。在 option_list 中的選項在 standard_option_list 中的任何選項(一個可能由 OptionParser 子類設定的類屬性)之後,但在任何版本或 help 選項之前新增。已棄用;請在建立解析器後使用 add_option()

option_class (預設: optparse.Option)

add_option() 中向解析器新增選項時使用的類。

version (預設: None)

當用戶提供版本選項時要列印的版本字串。 如果您為 version 提供一個真值,optparse 將自動新增一個版本選項,其唯一選項字串為 --version。子字串 %prog 的擴充套件方式與 usage 相同。

conflict_handler (預設: "error")

指定當具有衝突選項字串的選項新增到解析器時要執行的操作;請參閱 選項之間的衝突 部分。

description (預設: None)

一段文字,簡要概述您的程式。optparse 將重新格式化此段落以適應當前終端寬度,並在使用者請求幫助時列印(在 usage 之後,但在選項列表之前)。

formatter (預設: 一個新的 IndentedHelpFormatter)

一個 optparse.HelpFormatter 的例項,將用於列印幫助文字。optparse 為此目的提供了兩個具體的類:IndentedHelpFormatter 和 TitledHelpFormatter。

add_help_option (預設: True)

如果為 true,optparse 將向解析器新增一個幫助選項(選項字串為 -h--help)。

prog

usageversion 中擴充套件 %prog 時使用的字串,而不是 os.path.basename(sys.argv[0])

epilog (預設: None)

在選項幫助之後列印的一段幫助文字。

填充解析器

有幾種方法可以使用選項填充解析器。首選方法是使用 OptionParser.add_option(),如 教程 部分所示。add_option() 可以透過以下兩種方式之一呼叫

  • 將 Option 例項(由 make_option() 返回)傳遞給它

  • 將任何組合的位置引數和關鍵字引數傳遞給它,這些引數是 make_option()(即 Option 建構函式)可以接受的,它將為您建立 Option 例項

另一種方法是將預先構建的 Option 例項列表傳遞給 OptionParser 建構函式,如下所示

option_list = [
    make_option("-f", "--filename",
                action="store", type="string", dest="filename"),
    make_option("-q", "--quiet",
                action="store_false", dest="verbose"),
    ]
parser = OptionParser(option_list=option_list)

(make_option() 是用於建立 Option 例項的工廠函式;目前它是 Option 建構函式的別名。未來版本的 optparse 可能會將 Option 分為幾個類,而 make_option() 將選擇要例項化的正確類。不要直接例項化 Option。)

定義選項

每個 Option 例項代表一組同義的命令列選項字串,例如 -f--file。 您可以指定任意數量的短或長選項字串,但您必須至少指定一個整體選項字串。

建立 Option 例項的規範方法是使用 OptionParseradd_option() 方法。

OptionParser.add_option(option)
OptionParser.add_option(*opt_str, attr=value, ...)

要定義僅具有短選項字串的選項

parser.add_option("-f", attr=value, ...)

要定義僅具有長選項字串的選項

parser.add_option("--foo", attr=value, ...)

關鍵字引數定義新 Option 物件的屬性。最重要的選項屬性是 action,它在很大程度上決定了其他哪些屬性是相關的或必需的。如果您傳遞不相關的選項屬性,或未能傳遞必需的選項屬性,optparse 將引發 OptionError 異常,解釋您的錯誤。

選項的動作確定當 optparse 在命令列上遇到此選項時執行的操作。optparse 中硬編碼的標準選項動作是

"store"

儲存此選項的引數(預設)

"store_const"

儲存一個常量值,透過 Option.const 預先設定

"store_true"

儲存 True

"store_false"

儲存 False

"append"

將此選項的引數附加到列表中

"append_const"

將一個常量值附加到列表中,透過 Option.const 預先設定

"count"

將計數器加一

"callback"

呼叫指定的函式

"help"

列印一條用法訊息,包括所有選項及其文件

(如果您不提供動作,則預設值為 "store"。對於此動作,您還可以提供 typedest 選項屬性;請參閱 標準選項動作。)

如您所見,大多數動作都涉及在某處儲存或更新值。optparse 始終為此建立一個特殊的物件,通常稱為 options,它是 optparse.Values 的例項。

class optparse.Values

一個物件,將已解析的引數名稱和值作為屬性儲存。通常在呼叫 OptionParser.parse_args() 時建立,並且可以透過傳遞給 OptionParser.parse_args() 的 *values* 引數的自定義子類來覆蓋(如 解析引數 中所述)。

選項引數(和各種其他值)根據 dest(目標)選項屬性儲存為此物件的屬性。

例如,當您呼叫

parser.parse_args()

optparse 執行的第一件事之一是建立 options 物件

options = Values()

如果在此解析器中定義的選項之一是

parser.add_option("-f", "--file", action="store", type="string", dest="filename")

並且正在解析的命令列包含以下任何內容

-ffoo
-f foo
--file=foo
--file foo

然後,optparse 在看到此選項時,將執行相當於

options.filename = "foo"

typedest 選項屬性幾乎與 action 一樣重要,但是 action 是對 *所有* 選項都有意義的唯一屬性。

選項屬性

class optparse.Option

一個單獨的命令列引數,透過關鍵字傳遞給建構函式的各種屬性。通常使用 OptionParser.add_option() 建立,而不是直接建立,並且可以透過傳遞給 OptionParseroption_class 引數由自定義類重寫。

以下選項屬性可以作為關鍵字引數傳遞給 OptionParser.add_option()。如果您傳遞的選項屬性與特定選項不相關,或者未能傳遞必需的選項屬性,optparse 將引發 OptionError 異常。

Option.action

(預設值:"store")

確定 optparse 在命令列上看到此選項時的行為;可用選項記錄在此處

Option.type

(預設值:"string")

此選項期望的引數型別(例如,"string""int");可用的選項型別記錄在此處

Option.dest

(預設值:從選項字串派生)

如果選項的操作意味著在某個地方寫入或修改值,則此屬性告訴 optparse 將其寫入何處:dest 命名 options 物件的屬性,optparse 在解析命令列時構建該物件。

Option.default

如果命令列上未看到該選項,則用於此選專案標的預設值。另請參閱 OptionParser.set_defaults()

Option.nargs

(預設值:1)

當看到此選項時,應該消耗多少個 type 型別的引數。如果 > 1,optparse 將把值元組儲存到 dest

Option.const

對於儲存常量值的操作,要儲存的常量值。

Option.choices

對於型別為 "choice" 的選項,使用者可以選擇的字串列表。

Option.callback

對於操作為 "callback" 的選項,看到此選項時要呼叫的可呼叫物件。有關傳遞給可呼叫物件的引數的詳細資訊,請參閱 選項回撥 部分。

Option.callback_args
Option.callback_kwargs

在四個標準回撥引數之後傳遞給 callback 的其他位置和關鍵字引數。

Option.help

當用戶提供 help 選項(例如 --help)後列出所有可用選項時,為此選項列印的幫助文字。 如果沒有提供幫助文字,則將列出該選項,但不顯示幫助文字。 要隱藏此選項,請使用特殊值 optparse.SUPPRESS_HELP

Option.metavar

(預設值:從選項字串派生)

列印幫助文字時要使用的選項引數的替代符。 有關示例,請參見 教程 部分。

標準選項操作

各種選項操作的要求和效果略有不同。大多數操作都有一些相關的選項屬性,您可以指定這些屬性來指導 optparse 的行為;少數操作具有必需的屬性,您必須為使用該操作的任何選項指定這些屬性。

  • "store" [相關: type, dest, nargs, choices]

    該選項後面必須跟一個引數,該引數根據 type 轉換為一個值,並存儲在 dest 中。如果 nargs > 1,則將從命令列消耗多個引數;所有引數將根據 type 進行轉換,並作為元組儲存到 dest 中。請參閱標準選項型別部分。

    如果提供了 choices (字串列表或元組),則型別預設為 "choice"

    如果未提供 type,則預設為 "string"

    如果未提供 dest,則 optparse 從第一個長選項字串派生目標(例如,--foo-bar 意味著 foo_bar)。如果沒有長選項字串,則 optparse 從第一個短選項字串派生目標(例如,-f 意味著 f)。

    示例

    parser.add_option("-f")
    parser.add_option("-p", type="float", nargs=3, dest="point")
    

    解析命令列時

    -f foo.txt -p 1 -3.5 4 -fbar.txt
    

    optparse 將設定

    options.f = "foo.txt"
    options.point = (1.0, -3.5, 4.0)
    options.f = "bar.txt"
    
  • "store_const" [必需:const;相關:dest]

    const 儲存在 dest 中。

    示例

    parser.add_option("-q", "--quiet",
                      action="store_const", const=0, dest="verbose")
    parser.add_option("-v", "--verbose",
                      action="store_const", const=1, dest="verbose")
    parser.add_option("--noisy",
                      action="store_const", const=2, dest="verbose")
    

    如果看到 --noisyoptparse 將設定

    options.verbose = 2
    
  • "store_true" [相關:dest]

    "store_const" 的一個特殊情況,將 True 儲存到 dest 中。

  • "store_false" [相關: dest]

    "store_true" 類似,但儲存的是 False

    示例

    parser.add_option("--clobber", action="store_true", dest="clobber")
    parser.add_option("--no-clobber", action="store_false", dest="clobber")
    
  • "append" [相關: type, dest, nargs, choices]

    該選項後面必須跟一個引數,該引數將被附加到 dest 中的列表。如果未為 dest 提供預設值,則當 optparse 第一次在命令列上遇到此選項時,會自動建立一個空列表。 如果 nargs > 1,則會消耗多個引數,並將長度為 nargs 的元組附加到 dest

    typedest 的預設值與 "store" 操作的預設值相同。

    示例

    parser.add_option("-t", "--tracks", action="append", type="int")
    

    如果在命令列上看到 -t3optparse 將執行以下等效操作:

    options.tracks = []
    options.tracks.append(int("3"))
    

    如果稍後看到 --tracks=4,它會執行以下操作:

    options.tracks.append(int("4"))
    

    append 操作在選項的當前值上呼叫 append 方法。這意味著指定的任何預設值都必須具有 append 方法。這也意味著如果預設值不為空,則預設元素將出現在選項的已解析值中,並且來自命令列的任何值都將附加在這些預設值之後。

    >>> parser.add_option("--files", action="append", default=['~/.mypkg/defaults'])
    >>> opts, args = parser.parse_args(['--files', 'overrides.mypkg'])
    >>> opts.files
    ['~/.mypkg/defaults', 'overrides.mypkg']
    
  • "append_const" [必需: const; 相關: dest]

    "store_const" 類似,但值 const 會附加到 dest 中;與 "append" 一樣,dest 預設為 None,並且在第一次遇到該選項時會自動建立一個空列表。

  • "count" [相關: dest]

    遞增儲存在 dest 的整數。如果未提供預設值,則 dest 會在第一次遞增之前設定為零。

    示例

    parser.add_option("-v", action="count", dest="verbosity")
    

    第一次在命令列上看到 -v 時,optparse 將執行以下等效操作:

    options.verbosity = 0
    options.verbosity += 1
    

    每次後續出現 -v 都會導致:

    options.verbosity += 1
    
  • "callback" [必需: callback; 相關: type, nargs, callback_args, callback_kwargs]

    呼叫 callback 指定的函式,其呼叫方式如下:

    func(option, opt_str, value, parser, *args, **kwargs)
    

    有關更多詳細資訊,請參閱 選項回撥 部分。

  • "help"

    為當前選項解析器中的所有選項列印完整的幫助訊息。幫助訊息由傳遞給 OptionParser 建構函式的 usage 字串和傳遞給每個選項的 help 字串構成。

    如果未為某個選項提供 help 字串,它仍將列在幫助訊息中。要完全省略某個選項,請使用特殊值 optparse.SUPPRESS_HELP

    optparse 會自動向所有 OptionParser 新增 help 選項,因此通常不需要建立該選項。

    示例

    from optparse import OptionParser, SUPPRESS_HELP
    
    # usually, a help option is added automatically, but that can
    # be suppressed using the add_help_option argument
    parser = OptionParser(add_help_option=False)
    
    parser.add_option("-h", "--help", action="help")
    parser.add_option("-v", action="store_true", dest="verbose",
                      help="Be moderately verbose")
    parser.add_option("--file", dest="filename",
                      help="Input file to read data from")
    parser.add_option("--secret", help=SUPPRESS_HELP)
    

    如果 optparse 在命令列上看到 -h--help,它將向 stdout 列印類似於以下幫助訊息的內容(假設 sys.argv[0]"foo.py"

    Usage: foo.py [options]
    
    Options:
      -h, --help        Show this help message and exit
      -v                Be moderately verbose
      --file=FILENAME   Input file to read data from
    

    列印幫助訊息後,optparse 將使用 sys.exit(0) 終止你的程序。

  • “版本”

    將提供給 OptionParser 的版本號列印到 stdout 並退出。版本號實際上由 OptionParser 的 print_version() 方法格式化和列印。通常僅在向 OptionParser 建構函式提供 version 引數時才相關。與 help 選項一樣,你很少會建立 version 選項,因為 optparse 會在需要時自動新增它們。

標準選項型別

optparse 有五種內建的選項型別:"string""int""choice""float""complex"。如果需要新增新的選項型別,請參閱 擴充套件 optparse 部分。

字串選項的引數不會以任何方式進行檢查或轉換:命令列上的文字按原樣儲存在目標中(或傳遞給回撥)。

整數引數(型別為 "int")的解析方式如下:

  • 如果數字以 0x 開頭,則將其解析為十六進位制數字

  • 如果數字以 0 開頭,則將其解析為八進位制數字

  • 如果數字以 0b 開頭,則將其解析為二進位制數字

  • 否則,將數字解析為十進位制數字

轉換是透過呼叫具有適當基數(2、8、10 或 16)的 int() 完成的。如果此操作失敗,optparse 也會失敗,但會顯示更有用的錯誤訊息。

"float""complex" 選項引數會直接使用 float()complex() 進行轉換,並採用類似的錯誤處理方式。

"choice" 選項是 "string" 選項的一個子型別。choices 選項屬性(一個字串序列)定義了允許的選項引數集合。 optparse.check_choice() 會將使用者提供的選項引數與此主列表進行比較,如果提供了無效的字串,則會引發 OptionValueError 異常。

解析引數

建立和填充 OptionParser 的全部意義在於呼叫其 parse_args() 方法。

OptionParser.parse_args(args=None, values=None)

解析在 args 中找到的命令列選項。

輸入引數為

args

要處理的引數列表(預設值:sys.argv[1:]

values

一個 Values 物件,用於儲存選項引數(預設值:Values 的新例項)– 如果您提供一個現有物件,選項預設值將不會在其上初始化

返回值是一對 (options, args),其中

options

與作為 values 傳入的物件相同,或者是由 optparse 建立的 optparse.Values 例項

args

所有選項處理完畢後剩餘的位置引數

最常見的用法是不提供任何關鍵字引數。如果您提供 values,它將透過重複呼叫 setattr() 進行修改(大致對於儲存到選專案標中的每個選項引數呼叫一次),並由 parse_args() 返回。

如果 parse_args() 在引數列表中遇到任何錯誤,它會呼叫 OptionParser 的 error() 方法,並提供適當的終端使用者錯誤訊息。這最終會終止您的程序,並返回退出狀態 2(傳統的 Unix 命令列錯誤退出狀態)。

查詢和操作選項解析器

選項解析器的預設行為可以進行少量自定義,您也可以檢視您的選項解析器,瞭解其中包含的內容。OptionParser 提供了幾種方法來幫助您

OptionParser.disable_interspersed_args()

設定解析在第一個非選項處停止。例如,如果 -a-b 都是不帶引數的簡單選項,optparse 通常接受此語法

prog -a arg1 -b arg2

並將其視為等同於

prog -a -b arg1 arg2

要停用此功能,請呼叫 disable_interspersed_args()。這將恢復傳統的 Unix 語法,其中選項解析在第一個非選項引數處停止。

如果您的命令處理器執行另一個具有自身選項的命令,並且您想確保這些選項不會混淆,請使用此方法。例如,每個命令可能具有不同的選項集。

OptionParser.enable_interspersed_args()

設定解析在第一個非選項處不停止,允許將開關與命令引數交錯。這是預設行為。

OptionParser.get_option(opt_str)

返回具有選項字串 opt_str 的 Option 例項,如果沒有具有該選項字串的選項,則返回 None

OptionParser.has_option(opt_str)

如果 OptionParser 具有帶有選項字串 opt_str 的選項(例如,-q--verbose),則返回 True

OptionParser.remove_option(opt_str)

如果 OptionParser 具有與 opt_str 對應的選項,則會刪除該選項。如果該選項提供了任何其他選項字串,則所有這些選項字串都會變為無效。如果 opt_str 未出現在屬於此 OptionParser 的任何選項中,則會引發 ValueError 異常。

選項之間的衝突

如果您不小心,很容易定義具有衝突選項字串的選項

parser.add_option("-n", "--dry-run", ...)
...
parser.add_option("-n", "--noisy", ...)

(如果您定義了自己的具有某些標準選項的 OptionParser 子類,則尤其如此。)

每次新增選項時,optparse 都會檢查與現有選項的衝突。如果發現任何衝突,它會呼叫當前的衝突處理機制。您可以在建構函式中設定衝突處理機制

parser = OptionParser(..., conflict_handler=handler)

或者透過單獨的呼叫

parser.set_conflict_handler(handler)

可用的衝突處理程式是

"error"(預設)

假設選項衝突是程式設計錯誤,並引發 OptionConflictError 異常

"resolve"

智慧地解決選項衝突(請參閱下文)

例如,讓我們定義一個 OptionParser,它可以智慧地解決衝突,並向其中新增衝突選項

parser = OptionParser(conflict_handler="resolve")
parser.add_option("-n", "--dry-run", ..., help="do no harm")
parser.add_option("-n", "--noisy", ..., help="be noisy")

此時,optparse 檢測到先前新增的選項已在使用 -n 選項字串。由於 conflict_handler"resolve",因此它透過從早期選項的選項字串列表中刪除 -n 來解決這種情況。現在,--dry-run 是使用者啟用該選項的唯一方法。如果使用者請求幫助,幫助訊息將反映這一點

Options:
  --dry-run     do no harm
  ...
  -n, --noisy   be noisy

可以逐漸刪除先前新增的選項的選項字串,直到沒有剩餘的選項字串,並且使用者無法從命令列呼叫該選項。在這種情況下,optparse 會完全刪除該選項,因此它不會顯示在幫助文字或任何其他位置。繼續使用我們現有的 OptionParser

parser.add_option("--dry-run", ..., help="new dry-run option")

此時,原始的 -n/--dry-run 選項不再可訪問,因此 optparse 會將其刪除,留下此幫助文字

Options:
  ...
  -n, --noisy   be noisy
  --dry-run     new dry-run option

清理

OptionParser 例項有幾個迴圈引用。這對於 Python 的垃圾回收器來說不應該是一個問題,但是您可能希望透過在完成 OptionParser 後呼叫 destroy() 來顯式地斷開迴圈引用。這在長執行的應用程式中特別有用,在這些應用程式中,大型物件圖可以從您的 OptionParser 訪問。

其他方法

OptionParser 支援其他幾種公共方法

OptionParser.set_usage(usage)

根據上面為 usage 建構函式關鍵字引數描述的規則設定 usage 字串。傳遞 None 會設定預設 usage 字串;使用 optparse.SUPPRESS_USAGE 來抑制 usage 訊息。

OptionParser.print_usage(file=None)

將當前程式的使用資訊(self.usage)列印到檔案(預設為 stdout)。在 self.usage 中出現的任何字串 %prog 都會被替換為當前程式的名稱。如果 self.usage 為空或未定義,則不執行任何操作。

OptionParser.get_usage()

print_usage() 相同,但返回使用字串而不是列印它。

OptionParser.set_defaults(dest=value, ...)

一次為多個選專案標設定預設值。使用 set_defaults() 是設定選項預設值的首選方法,因為多個選項可以共享同一個目標。例如,如果多個“模式”選項都設定相同的目標,則其中任何一個都可以設定預設值,並且最後一個會生效。

parser.add_option("--advanced", action="store_const",
                  dest="mode", const="advanced",
                  default="novice")    # overridden below
parser.add_option("--novice", action="store_const",
                  dest="mode", const="novice",
                  default="advanced")  # overrides above setting

為了避免這種混亂,請使用 set_defaults()

parser.set_defaults(mode="advanced")
parser.add_option("--advanced", action="store_const",
                  dest="mode", const="advanced")
parser.add_option("--novice", action="store_const",
                  dest="mode", const="novice")

選項回撥

optparse 的內建動作和型別不足以滿足您的需求時,您有兩個選擇:擴充套件 optparse 或定義一個回撥選項。擴充套件 optparse 更通用,但對於許多簡單的情況來說是多餘的。通常,一個簡單的回撥就足夠了。

定義回撥選項有兩個步驟

  • 使用 "callback" 動作定義選項本身

  • 編寫回調;這是一個函式(或方法),它至少接受四個引數,如下所述

定義回撥選項

與往常一樣,定義回撥選項的最簡單方法是使用 OptionParser.add_option() 方法。除了 action 之外,您必須指定的唯一選項屬性是 callback,即要呼叫的函式。

parser.add_option("-c", action="callback", callback=my_callback)

callback 是一個函式(或其他可呼叫物件),因此在建立此回撥選項時,您必須已經定義了 my_callback()。在這個簡單的例子中,optparse 甚至不知道 -c 是否接受任何引數,這通常意味著該選項不接受任何引數—命令列上僅僅存在 -c 就足夠了。但在某些情況下,您可能希望您的回撥使用任意數量的命令列引數。這就是編寫回調變得棘手的地方;本節稍後將介紹它。

optparse 總是將四個特定的引數傳遞給您的回撥,並且只有在您透過 callback_argscallback_kwargs 指定它們時,它才會傳遞額外的引數。因此,最小的回撥函式簽名是

def my_callback(option, opt, value, parser):

下面描述了回撥的四個引數。

在定義回撥選項時,您還可以提供其他幾個選項屬性

type

具有通常的含義:與 "store""append" 動作一樣,它指示 optparse 使用一個引數並將其轉換為 type。但是,optparse 不是將轉換後的值儲存在任何地方,而是將其傳遞給您的回撥函式。

nargs

也具有其通常的含義:如果提供且 > 1,則 optparse 將使用 nargs 個引數,每個引數都必須可轉換為 type。然後,它將轉換後的值元組傳遞給您的回撥。

callback_args

要傳遞給回撥的額外位置引數的元組

callback_kwargs

要傳遞給回撥的額外關鍵字引數的字典

如何呼叫回撥

所有回撥都按如下方式呼叫

func(option, opt_str, value, parser, *args, **kwargs)

其中:

選項

是呼叫回撥的 Option 例項

opt_str

是在命令列上看到的觸發回撥的選項字串。(如果使用了縮寫的長選項,opt_str 將是完整的、規範的選項字串—例如,如果使用者在命令列上輸入 --foo 作為 --foobar 的縮寫,則 opt_str 將是 "--foobar"。)

value

是在命令列上看到的此選項的引數。optparse 僅在設定了 type 時才會期望引數;value 的型別將是選項型別所暗示的型別。如果此選項的 typeNone(不期望引數),則 value 將為 None。如果 nargs > 1,則 value 將是適當型別的值元組。

parser

是驅動整個過程的 OptionParser 例項,主要是因為它可以透過其例項屬性訪問其他一些有趣的資料

parser.largs

當前剩餘引數列表,即已被消耗但既不是選項也不是選項引數的引數。請隨意修改 parser.largs,例如,向其中新增更多引數。(此列表將成為 args,即 parse_args() 的第二個返回值。)

parser.rargs

當前剩餘引數列表,即刪除 opt_strvalue(如果適用)之後,並且只有它們之後的引數仍然存在。請隨意修改 parser.rargs,例如,透過使用更多引數。

parser.values

預設情況下儲存選項值的物件(optparse.OptionValues 的例項)。這允許回撥使用與 optparse 的其餘部分相同的機制來儲存選項值;您無需使用全域性變數或閉包。您還可以訪問或修改命令列上已遇到的任何選項的值。

args

是透過 callback_args 選項屬性提供的任意位置引數的元組。

kwargs

是透過 callback_kwargs 提供的任意關鍵字引數的字典。

在回撥中引發錯誤

如果選項或其引數存在任何問題,回撥函式應引發 OptionValueError 異常。optparse 會捕獲此異常並終止程式,並將您提供的錯誤訊息列印到 stderr。您的訊息應該清晰、簡潔、準確,並提及出錯的選項。否則,使用者將很難弄清楚他們做錯了什麼。

回撥示例 1:簡單的回撥

這是一個回撥選項的示例,它不帶任何引數,僅記錄該選項已被看到

def record_foo_seen(option, opt_str, value, parser):
    parser.values.saw_foo = True

parser.add_option("--foo", action="callback", callback=record_foo_seen)

當然,您可以使用 "store_true" 動作來實現此目的。

回撥示例 2:檢查選項順序

這是一個稍微有趣一點的示例:記錄 -a 被看到的事實,但如果它在命令列中出現在 -b 之後,則會崩潰。

def check_order(option, opt_str, value, parser):
    if parser.values.b:
        raise OptionValueError("can't use -a after -b")
    parser.values.a = 1
...
parser.add_option("-a", action="callback", callback=check_order)
parser.add_option("-b", action="store_true", dest="b")

回撥示例 3:檢查選項順序(通用化)

如果您想為幾個類似的選項重用此回撥(設定標誌,但如果 -b 已經被看到則崩潰),則需要做一些工作:錯誤訊息和它設定的標誌必須通用化。

def check_order(option, opt_str, value, parser):
    if parser.values.b:
        raise OptionValueError("can't use %s after -b" % opt_str)
    setattr(parser.values, option.dest, 1)
...
parser.add_option("-a", action="callback", callback=check_order, dest='a')
parser.add_option("-b", action="store_true", dest="b")
parser.add_option("-c", action="callback", callback=check_order, dest='c')

回撥示例 4:檢查任意條件

當然,您可以在其中放置任何條件,而不僅僅是檢查已經定義的選項的值。例如,如果您有不應在滿月時呼叫的選項,您只需這樣做

def check_moon(option, opt_str, value, parser):
    if is_moon_full():
        raise OptionValueError("%s option invalid when moon is full"
                               % opt_str)
    setattr(parser.values, option.dest, 1)
...
parser.add_option("--foo",
                  action="callback", callback=check_moon, dest="foo")

is_moon_full() 的定義留給讀者作為練習。)

回撥示例 5:固定引數

當您定義接受固定數量引數的回撥選項時,事情會變得稍微有趣一些。指定回撥選項接受引數類似於定義 "store""append" 選項:如果定義 type,則該選項接受一個引數,該引數必須可以轉換為該型別;如果您進一步定義 nargs,則該選項接受 nargs 個引數。

這是一個僅模擬標準 "store" 動作的示例

def store_value(option, opt_str, value, parser):
    setattr(parser.values, option.dest, value)
...
parser.add_option("--foo",
                  action="callback", callback=store_value,
                  type="int", nargs=3, dest="foo")

請注意,optparse 負責為您消耗 3 個引數並將它們轉換為整數;您只需要儲存它們即可。(或者其他任何操作;顯然,此示例不需要回調。)

回撥示例 6:可變引數

當您希望選項接受可變數量的引數時,事情會變得複雜。對於這種情況,您必須編寫一個回撥,因為 optparse 不提供任何內建功能。並且您必須處理 optparse 通常為您處理的傳統 Unix 命令列解析的某些複雜性。特別是,回撥應實現裸 --- 引數的傳統規則

  • --- 可以是選項引數

  • -- (如果不是某個選項的引數):停止命令列處理並丟棄 --

  • - (如果不是某個選項的引數):停止命令列處理但保留 -(將其附加到 parser.largs

如果您想要一個接受可變數量引數的選項,則有幾個微妙的、棘手的問題需要擔心。您選擇的確切實現將基於您願意為應用程式做出的權衡(這就是為什麼 optparse 不直接支援這種型別的東西)。

不過,這裡有一個針對具有可變引數的選項的回撥的嘗試

def vararg_callback(option, opt_str, value, parser):
    assert value is None
    value = []

    def floatable(str):
        try:
            float(str)
            return True
        except ValueError:
            return False

    for arg in parser.rargs:
        # stop on --foo like options
        if arg[:2] == "--" and len(arg) > 2:
            break
        # stop on -a, but not on -3 or -3.0
        if arg[:1] == "-" and len(arg) > 1 and not floatable(arg):
            break
        value.append(arg)

    del parser.rargs[:len(value)]
    setattr(parser.values, option.dest, value)

...
parser.add_option("-c", "--callback", dest="vararg_attr",
                  action="callback", callback=vararg_callback)

擴充套件 optparse

由於 optparse 如何解釋命令列選項的兩個主要控制因素是每個選項的動作和型別,因此最可能的擴充套件方向是新增新的動作和新的型別。

新增新型別

要新增新型別,您需要定義 optparseOption 類的自定義子類。此類具有幾個屬性,這些屬性定義了 optparse 的型別:TYPESTYPE_CHECKER

Option.TYPES

型別名稱的元組;在您的子類中,只需定義一個新的元組 TYPES,該元組建立在標準元組的基礎上。

Option.TYPE_CHECKER

一個將型別名稱對映到型別檢查函式的字典。型別檢查函式具有以下簽名

def check_mytype(option, opt, value)

其中 option 是一個 Option 例項,opt 是一個選項字串(例如,-f),而 value 是來自命令列、必須檢查並轉換為您所需的型別的字串。check_mytype() 應返回假設型別 mytype 的物件。型別檢查函式返回的值將最終出現在 OptionParser.parse_args() 返回的 OptionValues 例項中,或作為 value 引數傳遞給回撥。

如果您的型別檢查函式遇到任何問題,則應引發 OptionValueError 異常。OptionValueError 接受一個字串引數,該引數按原樣傳遞給 OptionParsererror() 方法,該方法依次前置程式名稱和字串 "error:",並將所有內容列印到 stderr,然後終止程序。

這是一個簡單的示例,演示如何新增 "complex" 選項型別以在命令列上解析 Python 風格的複數。(這甚至比以前更傻了,因為 optparse 1.3 添加了對複數的內建支援,但沒關係。)

首先,必要的匯入

from copy import copy
from optparse import Option, OptionValueError

您需要首先定義型別檢查器,因為它稍後會被引用(在您的 Option 子類的 TYPE_CHECKER 類屬性中)

def check_complex(option, opt, value):
    try:
        return complex(value)
    except ValueError:
        raise OptionValueError(
            "option %s: invalid complex value: %r" % (opt, value))

最後,Option 子類

class MyOption (Option):
    TYPES = Option.TYPES + ("complex",)
    TYPE_CHECKER = copy(Option.TYPE_CHECKER)
    TYPE_CHECKER["complex"] = check_complex

(如果我們沒有 copy() Option.TYPE_CHECKER,我們將最終修改 optparse 的 Option 類的 TYPE_CHECKER 屬性。由於這是 Python,除了良好的禮儀和常識之外,沒有任何東西能阻止您這樣做。)

就這樣!現在,您可以編寫一個指令碼,該指令碼像任何其他基於 optparse 的指令碼一樣使用新的選項型別,只是您必須指示 OptionParser 使用 MyOption 而不是 Option

parser = OptionParser(option_class=MyOption)
parser.add_option("-c", type="complex")

或者,您可以構建自己的選項列表並將其傳遞給 OptionParser;如果您不以上述方式使用 add_option(),則無需告知 OptionParser 使用哪個選項類

option_list = [MyOption("-c", action="store", type="complex", dest="c")]
parser = OptionParser(option_list=option_list)

新增新動作

新增新的動作會稍微複雜一些,因為您需要理解 optparse 對動作有幾種分類。

“儲存”動作

導致 optparse 將值儲存到當前 OptionValues 例項的屬性中的動作;這些選項需要在 Option 建構函式中提供 dest 屬性。

“型別化”動作

從命令列獲取值並期望它是特定型別的動作;或者更確切地說,是可以轉換為特定型別的字串。這些選項需要在 Option 建構函式中提供 type 屬性。

這些是重疊的集合:一些預設的“儲存”動作是 "store""store_const""append""count",而預設的“型別化”動作是 "store""append""callback"

當您新增一個動作時,您需要透過將其列在 Option 的以下至少一個類屬性中來對其進行分類(所有類屬性都是字串列表)

Option.ACTIONS

所有動作都必須列在 ACTIONS 中。

Option.STORE_ACTIONS

“儲存”動作會額外列在此處。

Option.TYPED_ACTIONS

“型別化”動作會額外列在此處。

Option.ALWAYS_TYPED_ACTIONS

始終需要型別的動作(即其選項始終需要值的動作)會額外列在此處。這唯一的作用是 optparse 將預設型別 "string" 分配給那些沒有顯式型別且其動作在 ALWAYS_TYPED_ACTIONS 中列出的選項。

為了真正實現您的新動作,您必須重寫 Option 的 take_action() 方法,並新增一個可以識別您的動作的情況。

例如,讓我們新增一個 "extend" 動作。這類似於標準的 "append" 動作,但是 "extend" 不是從命令列獲取單個值並將其附加到現有列表中,而是會獲取以逗號分隔的字串中的多個值,並用它們擴充套件現有列表。也就是說,如果 --names 是一個 "extend" 型別的 "string" 選項,則命令列

--names=foo,bar --names blah --names ding,dong

將產生一個列表

["foo", "bar", "blah", "ding", "dong"]

再次定義 Option 的子類

class MyOption(Option):

    ACTIONS = Option.ACTIONS + ("extend",)
    STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
    TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
    ALWAYS_TYPED_ACTIONS = Option.ALWAYS_TYPED_ACTIONS + ("extend",)

    def take_action(self, action, dest, opt, value, values, parser):
        if action == "extend":
            lvalue = value.split(",")
            values.ensure_value(dest, []).extend(lvalue)
        else:
            Option.take_action(
                self, action, dest, opt, value, values, parser)

值得注意的特點

  • "extend" 既期望命令列上的值,又在某處儲存該值,因此它同時進入 STORE_ACTIONSTYPED_ACTIONS

  • 為了確保 optparse 將預設型別 "string" 分配給 "extend" 動作,我們將 "extend" 動作也放在 ALWAYS_TYPED_ACTIONS 中。

  • MyOption.take_action() 僅實現這一個新動作,並將控制權傳遞迴 Option.take_action() 以進行標準的 optparse 動作。

  • values 是 optparse_parser.Values 類的例項,它提供了非常有用的 ensure_value() 方法。ensure_value() 本質上是帶有安全閥的 getattr();它被呼叫為

    values.ensure_value(attr, value)
    

    如果 valuesattr 屬性不存在或為 None,則 ensure_value() 首先將其設定為 value,然後返回 value。這對於諸如 "extend""append""count" 之類的動作非常方便,它們都在變數中累積資料,並期望該變數為特定型別(前兩個為列表,後者為整數)。使用 ensure_value() 意味著使用您的動作的指令碼無需擔心為相關選專案標設定預設值;它們可以將預設值保留為 None,而 ensure_value() 會在需要時負責使其正確。

異常

exception optparse.OptionError

如果建立的 Option 例項包含無效或不一致的引數,則會引發此異常。

exception optparse.OptionConflictError

如果將衝突的選項新增到 OptionParser,則會引發此異常。

exception optparse.OptionValueError

如果在命令列中遇到無效的選項值,則會引發此異常。

exception optparse.BadOptionError

如果在命令列中傳遞了無效的選項,則會引發此異常。

exception optparse.AmbiguousOptionError

如果在命令列中傳遞了模稜兩可的選項,則會引發此異常。