命令行參數解析——argparse
背景
命令行參數解析
示例:
# 第一種
python taos_lttb.py a b
# 第二種
python taos_lttb.py v=a a=b
# 第三種
python taos_lttb.py -v a -a b
以上三種是比較常見的傳參方式。究其根本,在Python中代表兩類參數:
-
args型:與輸入順序有關示例:
def func(a,b): pass #調用 func(*(a,b)) -
kwargs:與輸入順序無關,與形參名有關示例
def func(a=None,b=None): pass #調用 a1={'a':1,'b':2} a2={'b':2,'a':3} #示例1 func(**a1) #示例3 func(**a2)
具體應用過程中可能還會出現兩者混用的情況:
def func1(a,b,c=None,d=None):
pass
def func2(a,b,*,c=None,d=None):
pass
#這里*表示分隔符,用于分隔args和kwargs型參數
現在我們重新審視上述三種命令行調用方法,優劣顯而易見。
但"上什么山,唱什么歌"。每種調用方式都有其適應的場景,我們需要根據具體業務場景,做正確性抉擇。
接下來將對具體的參數解析方法進行介紹。
參數解析方法
目前比較常見的參數解析方式或相關方法如下:
sys.argv(python標準庫)argparse模塊(python標準庫)
sys.argv
sys模塊包含了一個名為argv的數組,其中包括以下內容:
argv[0]包含當前Python程序的名稱。argv[1:],列表的其余部分,包含傳遞給程序的所有Python命令行參數。
示例:
- 定義腳本(argv.py)
# argv.py
import sys
print(f"Name of the script : {sys.argv[0]=}")
print(f"Arguments of the script : {sys.argv[1:]=}")
- 在命令行開始調用
$ python argv.py un deux trois quatre
Name of the script : sys.argv[0]='argv.py'
Arguments of the script : sys.argv[1:]=['un', 'deux', 'trois', 'quatre']
輸出確認sys.argv[0]的內容是Python腳本argv.py,而sys.argv列表的其余元素包含腳本['un', 'deux', 'trois', 'quatre']的參數。
總而言之,sys.argv包含所有argv.py Python命令行參數。當Python解釋器執行Python程序時,它解析命令行并使用參數填充sys.argv。
對于kwargs型的參數,我們也可以采用類似的方式進行傳輸,只不過得到的參數有可能是:
第一種:基于等號=進行拆分,但是如果對應值如果包含=等號可能出現解析異常的問題;
sys.argv[1:]=['a1=un', 'a2=deux', 'a3=trois', 'a4=quatre']
第二種:將傳入的kwargs直接以JSON字符串的形式傳入,示例如下:
sys.argv[1:]='{"a1": "un", "a2": "deux", "a3": "trois", "a4": "quatre"}'
#然后直接json.loads,然后通過**的方式進行傳參
但是存在的問題:在命令行粘貼后,如果a1的鍵值是SQL語句可能出現參數截斷的問題,所以我們需要選擇另一種方法進行解析——argparse。
argparse
幫助文檔
示例
# -*- coding=utf-8-*-
import argparse
def _get_input_str(x):
"""強制處理單引號問題"""
return x.strip('"').strip("'")
class SQLAction(argparse.Action):
"""sql中空格的問題"""
def __call__(self, parser, namespace, values, option_string=None):
setattr(namespace, self.dest, ' '.join(values))
class MyAction(argparse.Action):
"""自定義示例"""
def __call__(self, parser, namespace, values, option_string=None):
tmp = []
for i in values:
tmp.extend(i.split())
# setattr(namespace, self.dest, ' '.join(values))
setattr(namespace, self.dest, tmp)
if __name__ == '__main__':
parser = argparse.ArgumentParser(allow_abbrev=False,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("-u", default='root', dest="user_name",
type=_get_input_str, nargs='?',
help="請輸入用戶名")
parser.add_argument('-sql', default=None, dest="select_com",
nargs='+',
help="sql查詢語句",
action=SQLAction)
parser.add_argument('-p', default="taosdata", dest='pwd',
help='用戶密碼', nargs='?',
type=_get_input_str)
parser.add_argument('-t', default=30, dest='timeout', type=int, nargs='?',
help="響應時間:秒")
parser.add_argument('-th', default=100000,
dest='thres', type=int, nargs='?',
help="閾值")
args = parser.parse_args()
input_kwargs = args.__dict__.copy()
input_kwargs["select_com"] = _get_input_str(input_kwargs["select_com"])
# input_kwargs["col_name"] = input_kwargs["col_name"][0].split()
print(f"input_kwargs={input_kwargs}")
調用示例:
(pymatest) E:\python_scripts\python>python argv.py -u root -sql "select * from table" -p 123456
input_kwargs={'user_name': 'root', 'select_com': 'select * from table', 'pwd': '123456', 'timeout': 30, 'thres': 100000}
argparse相關核心參數解釋:
-
allow_abbrev:如果縮寫是無歧義的,則允許縮寫長選項 (默認值:True); -
default:默認值; -
dest:被添加到parse_args()所返回對象上的屬性名,即變量名,也可以直接點是形參名; -
help: 幫助信息,是一個包含參數簡短描述的字符串;當用戶請求幫助時(一般是通過在命令行中使用-h或--help的方式),這些help描述將隨每個參數一同顯示:(pymatest) E:\python_scripts\python>python argv.py -h usage: argv.py [-h] [-u [USER_NAME]] [-sql SELECT_COM [SELECT_COM ...]] [-p [PWD]] [-t [TIMEOUT]] [-th [THRES]] optional arguments: -h, --help show this help message and exit -u [USER_NAME] 請輸入用戶名 -sql SELECT_COM [SELECT_COM ...] sql查詢語句 -p [PWD] 用戶密碼 -t [TIMEOUT] 響應時間:秒 -th [THRES] 閾值 -
type:命令行參數應當被轉換成的類型。默認情況下,解析器會將命令行參數當作簡單字符串讀入。 然而,命令行字符串經常應當被解讀為其他類型,例如float或int。add_argument()的type關鍵字允許執行任何必要的類型檢查和類型轉換。傳給
type的參數可以是任何接受單個字符串的可調用對象。 如果函數引發了ArgumentTypeError,TypeError或ValueError,異常會被捕獲并顯示經過良好格式化的錯誤消息。 其他異常類型則不會被處理。示例:
import argparse import pathlib parser = argparse.ArgumentParser() parser.add_argument('count', type=int) parser.add_argument('distance', type=float) parser.add_argument('street', type=ascii) parser.add_argument('code_point', type=ord) parser.add_argument('source_file', type=open) parser.add_argument('dest_file', type=argparse.FileType('w', encoding='latin-1')) parser.add_argument('datapath', type=pathlib.Path)-
不建議將
bool()函數用作類型轉換器。 它所做的只是將空字符串轉為False而將非空字符串轉為True。 這通常不是用戶所想要的。 -
通常,
type關鍵字是僅應被用于只會引發上述三種被支持的異常的簡單轉換的便捷選項。 任何具有更復雜錯誤處理或資源管理的轉換都應當在參數被解析后由下游代碼來完成。 -
例如,JSON 或 YAML 轉換具有復雜的錯誤情況,要求給出比
type關鍵字所能給出的更好的報告。JSONDecodeError將不會被良好地格式化而FileNotFound異常則完全不會被處理。 -
即使
FileType在用于type關鍵字時也存在限制。 如果一個參數使用了 FileType 并且有一個后續參數出錯,則將報告一個錯誤但文件并不會被自動關閉。 在此情況下,更好的做法是等待直到解析器運行完畢再使用with語句來管理文件。 -
對于簡單地檢查一組固定值的類型檢查器,請考慮改用 choices 關鍵字。
-
-
nargs:定義參數個數和形式。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'])?:如果可能的話,會從命令行中消耗一個參數,并產生一個單獨項。 如果當前沒有命令行參數,將會產生 default 值。 注意對于可選參數來說,還有一個額外情況 —— 出現了選項字符串但沒有跟隨命令行參數,在此情況下將會產生 const 值。 一些說明這種情況的例子如下:
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')*:所有當前命令行參數被聚集到一個列表中。注意通過nargs='*'來實現多個位置參數通常沒有意義,但是多個選項是可能的。+:和'*'類似,所有當前命令行參數被聚集到一個列表中。另外,當前沒有至少一個命令行參數時會產生一個錯誤信息。- 如果不提供
nargs命名參數,則消耗參數的數目將被 action 決定。通常這意味著單一項目(非列表)消耗單一命令行參數。
-
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') -
requires參數:定義哪些參數是必填哪些參數是選填的
parser = argparse.ArgumentParser()
parser.add_argument('--foo', required=True)
parser.parse_args(['--foo', 'BAR'])
Namespace(foo='BAR')
parser.parse_args([])
usage: [-h] --foo FOO
: error: the following arguments are required: --foo
-*或者--*:來源,用來定義參數指向
Standards標準
A few available standards provide some definitions and guidelines to promote consistency for implementing commands and their arguments. These are the main UNIX standards and references:
一些可用的標準提供了一些定義和指導方針,以促進實現命令及其參數的一致性。以下是主要的UNIX標準和參考:
- POSIX Utility ConventionsPOSIX實用程序約定
- GNU Standards for Command Line Interfaces
GNU命令行接口標準- docopt多科普特
The standards above define guidelines and nomenclatures for anything related to programs and Python command-line arguments. The following points are examples taken from those references:
上面的標準定義了與程序和Python命令行參數相關的任何內容的指南和術語。以下幾點是從這些參考文獻中摘錄的例子:
POSIX
:
- A program or utility is followed by options, option-arguments, and operands.
程序或實用程序后面是選項、選項參數和操作數。- All options should be preceded with a hyphen or minus (
-) delimiter character.
所有選項前面都應加上連字符或減號(-)分隔符。- Option-arguments should not be optional.
Option-arguments不應該是可選的。GNU
:
- All programs should support two standard options, which are
--versionand--help.
所有程序應支持兩個標準選項,即--version和--help。- Long-named options are equivalent to the single-letter Unix-style options. An example is
--debugand-d.
長名稱選項等同于單字母Unix樣式選項。一個例子是--debug和-d。docopt多科普特
:
- Short options can be stacked, meaning that
-abcis equivalent to-a -b -c.
短期權可以堆疊,這意味著-abc等同于-a -b -c。- Long options can have arguments specified after a space or the equals sign (
=). The long option--input=ARGis equivalent to--input ARG.
長選項可以在空格或等號(=)后指定參數。長選項--input=ARG相當于--input ARG。These standards define notations that are helpful when you describe a command. A similar notation can be used to display the usage of a particular command when you invoke it with the option
-hor--help.
這些標準定義了在描述命令時非常有用的符號。當您使用選項-h或--help調用特定命令時,可以使用類似的符號來顯示該命令的用法。The GNU standards are very similar to the POSIX standards but provide some modifications and extensions. Notably, they add the long option that’s a fully named option prefixed with two hyphens (
--). For example, to display the help, the regular option is-hand the long option is--help.
GNU標準與POSIX標準非常相似,但提供了一些修改和擴展。值得注意的是,他們添加了長選項,這是一個以兩個連字符(--)為前綴的完整命名選項。例如,要顯示幫助,常規選項為-h,長選項為--help。Note: You don’t need to follow those standards rigorously. Instead, follow the conventions that have been used successfully for years since the advent of UNIX. If you write a set of utilities for you or your team, then ensure that you stay consistent across the different utilities.
注意:您不需要嚴格遵循這些標準。相反,應該遵循自UNIX出現以來已成功使用多年的約定。如果您為您或您的團隊編寫了一組實用程序,那么請確保您在不同的實用程序中保持一致。
_get_input_str
用于處理命令行傳參過程中的一些字符串問題;
parser.add_argument("-u", dest="user_name",
type=str, nargs='?',
help="請輸入用戶名")
(pymatest) E:\python_scripts\python>python argv0.py -u root
input_kwargs={'user_name': 'root', 'select_com': 'aa', 'pwd': 'taosdata', 'timeout': 30, 'thres': 100000}
(pymatest) E:\python_scripts\python>python argv0.py -u "root"
input_kwargs={'user_name': 'root', 'select_com': 'aa', 'pwd': 'taosdata', 'timeout': 30, 'thres': 100000}
(pymatest) E:\python_scripts\python>python argv0.py -u 'root'
input_kwargs={'user_name': "'root'", 'select_com': 'aa', 'pwd': 'taosdata', 'timeout': 30, 'thres': 100000}
單引號時,字符串又被雙引號包裝了一層。
優化:
parser.add_argument("-u", dest="user_name",
type=_get_input_str, nargs='?',
help="請輸入用戶名")
調用:
(pymatest) E:\python_scripts\python>python argv0.py -u 'root'
input_kwargs={'user_name': 'root', 'select_com': 'aa', 'pwd': 'taosdata', 'timeout': 30, 'thres': 100000}
Action示例
class MyAction(argparse.Action):
"""自定義示例"""
def __call__(self, parser, namespace, values, option_string=None):
tmp = []
for i in values:
tmp.extend(i.split())
# setattr(namespace, self.dest, ' '.join(values))
setattr(namespace, self.dest, tmp)
Action 類實現了 Action API,它是一個返回可調用對象的可調用對象,返回的可調用對象可處理來自命令行的參數。 任何遵循此 API 的對象均可作為 action 形參傳給 add_argument()。
Action 的實例應當為可調用對象,因此所有子類都必須重載 __call__ 方法,該方法應當接受四個形參:
parser- 包含此動作的 ArgumentParser 對象。namespace- 將由parse_args()返回的Namespace對象。 大多數動作會使用setattr()為此對象添加屬性。values- 已關聯的命令行參數,并提供相應的類型轉換。 類型轉換由add_argument()的 type 關鍵字參數來指定。option_string- 被用來發起調用此動作的選項字符串。option_string參數是可選的,且此參數在動作關聯到位置參數時將被略去。
__call__ 方法可以執行任意動作,但通常將基于 dest 和 values 來設置 namespace 的屬性。

浙公網安備 33010602011771號