Python 命令行參數解析工具 argparse


為什么需要argparse

開門見山,舉一個簡易計算器代碼的例子,其中sys.argv用來讀取腳本執行時后面傳入的參數。

def calculator(x, y, operation):
    if "add" == operation:
        return x + y
    elif "mod" == operation:
        return x % y
    elif "sub" == operation:
        return x - y
    elif "div" == operation:
        return x / y
    elif "mul" == operation:
        return x * y


def main():
    print(calculator(sys.argv[1], sys.argv[2], sys.argv[3]))


if __name__ == '__main__':
    main()

我們定義了一個calculator方法來完成一些簡單的計算工作,這看來相當平凡,但對於用戶來說,在沒有良好的文檔支持的前提下,傳入不同參數有不同的行為,如果只有少量參數還可以接受,隨着參數的增加,方法會變得越來越不易使用。這時候便需要參數解析,argparse模塊便官方推薦的在optparse基礎上更進一步的改良版標准庫。讓我們在了解一下她的廬山真面目之前先通過一個例子來了解argparse相關特性。

相信小伙伴們都或多或少用過Linux系統,讓我們通過下面這個例子直觀的了解argparse能做什么。

# 只輸入ls,默認顯示當前目錄下內容
[root@host workarea]# ls
pythondemo  scripts
# 當我們給ls命令加一個參數,便會去找這個參數對應目錄下的內容
[root@host workarea]# ls pythondemo/
arg1.py  argparsedemo1.py  fangzhen.py  numpyapi.py  tools
# 我們也可以使用ls -[cmd]來改變行為,獲得更詳細的信息
[root@host workarea]# ls -l
total 8
drwxr-xr-x 3 root root 4096 Dec 14 14:05 pythondemo
drwxr-xr-x 2 root root 4096 Dec 14 14:29 scripts
# 如果我們想知道ls命令的其他用法和相關信息可以使用ls --help
[root@host workarea]# 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.

Mandatory arguments to long options are mandatory for short options too.
  -a, --all                  do not ignore entries starting with .
  -A, --almost-all           do not list implied . and ..
...

腳本傳入后的參數顯示的綁定,讓用戶更清楚自己在執行什么操作,並且給用戶一些提示信息在他忘記如何使用我們的腳本時,這便是我們要做的,當然如果參數數量不多,或者行為不復雜可以不使用。

argparse初體驗

#總體使用流程如下
import argparse
# 模板創建一個解析參數對象
parser = argparse.ArgumentParser()
# 用來指定程序需要接受的命令參數
parser.add_argument()
# 通過分析指定的參數返回一些數據
args = parser.parse_args()

我們直接試着用argparse對上面的例子進行改造,直觀感受下區別

def calculator(args):
    operation = args.operation
    x = args.x
    y = args.y
    if "add" == operation:
        return x + y
    elif "mod" == operation:
        return x % y
    elif "sub" == operation:
        return x - y
    elif "div" == operation:
        return x / y
    elif "mul" == operation:
        return x * y


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--x", type=float, default=1.0, help="What is the first number")
    parser.add_argument("--y", type=float, default=1.0, help="What is the second number")
    parser.add_argument("--operation", type=str, help="What operation? [add,mod,sub,div,mul]")
    args = parser.parse_args()
    print(args)
    print(calculator(args))


if __name__ == '__main__':
    main()

經過簡單的改造,調用calculator方法時,我們可以更清楚自己在做什么操作,並且可以根據幫助信息使用而不需要去閱讀源碼了,這真的節省了很多不必要的時間。

# 直接調用不加參數,會提示None,命名空間那行為print(args)
[root@host pythondemo]# python arg2.py 
Namespace(operation=None, x=1.0, y=1.0)
None
# 加上參數-h 或 --help我們就能看到幫助信息,感覺像模像樣
[root@host pythondemo]# python arg2.py -h
usage: arg2.py [-h] [--x X] [--y Y] [--operation OPERATION]

optional arguments:
  -h, --help            show this help message and exit
  --x X                 What is the first number
  --y Y                 What is the second number
  --operation OPERATION
                        What operation? [add,mod,sub,div,mul]
# 參數傳入方法,這里的等於號可以省略
[root@host pythondemo]# python arg2.py --x=2 --y=3 --operation=mul
6.0
# 當我們少輸入或者沒有輸入要求的參數
[root@host pythondemo]# python arg2.py 2
usage: arg2.py [-h] [--x X] [--y Y] [--operation OPERATION]
arg2.py: error: unrecognized arguments: 2

當然這並沒有完成我們的全部需求,我們還可以做的更好,那么我們就得深入了解下今天得主角argparse。

argparse詳解

模板創建argparse.ArgumentParser()

我們可以給解析模板來個簡單得標題,會在--help中顯示

argparse.ArgumentParser(description='sample demo')

如果我們不想用Linux風格的"-"或"--"來作為命令前綴,我們自定義如下

parser = argparse.ArgumentParser(prefix_chars='-+/')

模板創建時是默認添加-h和--help幫助信息的,如果我們不想要,寫可以去除掉

argparse.ArgumentParser(add_help=False)

我們也可以添加版本信息,會自動加入獲取版本信息的-v和--version命令

argparse.ArgumentParser(version='1.0')

重頭戲parser.add_argument()

直接在方法里加一個字符串"-a"或"--a"當在腳本后面調用傳入值后,都可以使用arg.a獲取傳入值,傳入值默認從sys.argv【1:】中獲得

parser.add_argument("-a")
args = parser.parse_args()
print(args)
print(args.a)

# 結果
λ python exam2.py --a=1
Namespace(a='1')
1

如果我們想改變訪問方式可以用dest參數

parser.add_argument("--a", dest="c")
args = parser.parse_args()
print(args)
print(args.c)

# 結果
λ python exam2.py --a=1    

Namespace(c='1')           
1

我們也可以不用變量顯示賦值的方式,不加“-”或“--”,這樣傳入值和參數定義的順序一樣,這種情況desk不奏效

parser.add_argument("a")
parser.add_argument("b")
args = parser.parse_args()
print(args)

# 結果
λ python exam2.py 1 2
Namespace(a='1', b='2')

當然我們也可以給傳入兩種接受方式,這種情況"-"開頭的為命令簡寫,獲取傳入參數用"--"后的屬性

parser.add_argument('-n', '--name', help="What's ur name")
args = parser.parse_args()
print(args)
print(args.name)

# 結果
λ python exam3.py -n=ling
Namespace(name='ling')
ling
λ python exam3.py --name=wang
Namespace(name='wang')
wang

默認我們傳入的值會當作字符串來處理,如果我們需要指定類型可以使用type參數,如上面計算器中定義所示,如果不指定type為int,便會報錯。默認支持的type類型有 int,float,open

parser.add_argument(type="")

如果確定動作需要傳入參數的個數,我們也可以加nargs做強制限制。["n":參數的絕對個數,"?":0或1個,"*":0或所以,"+":所有並且至少一個]

parser.add_argument(nargs="")

參數動作

argparse內置6種動作可以在解析到一個參數時進行觸發:

store保存參數值,可能會先將參數值轉換成另一個數據類型。若沒有顯式指定動作,則默認為該動作。

store_const保存的常量,如果觸發此動作,值是參數規格中提前被定義的值,而不能命令行傳入值。

store_ture/store_false保存相應的布爾值。這兩個動作被用於實現布爾開關。

append將值保存到一個列表中。若參數重復出現,則保存多個值。

append_const將一個定義在參數規格中的值保存到一個列表中。

version打印關於程序的版本信息,然后退出

用法如下所示:

parser.add_argument('-s', action='store', dest='simple_value', help='Store a simple value')
parser.add_argument('-c', action='store_const', dest='constant_value',
        const='value-to-store',
        help='Store a constant value')

parser.add_argument('-t', action='store_true', default=False,
        dest='boolean_switch',
        help='Set a switch to true')
parser.add_argument('-f', action='store_false', default=False,
        dest='boolean_switch',
        help='Set a switch to false')

parser.add_argument('-a', action='append', dest='collection',
        default=[],
        help='Add repeated values to a list')

parser.add_argument('-A', action='append_const', dest='const_collection',
        const='value-1-to-append',
        default=[],
        help='Add different values to list')
parser.add_argument('-B', action='append_const', dest='const_collection',
        const='value-2-to-append',
        help='Add different values to list')

parser.add_argument('--version', action='version', version='%(prog)s 1.0')
results = parser.parse_args()
print 'simple_value     =', results.simple_value
print 'constant_value   =', results.constant_value
print 'boolean_switch   =', results.boolean_switch
print 'collection       =', results.collection
print 'const_collection =', results.const_collection

# 結果
λ python argparse_action.py -s value

simple_value     = value
constant_value   = None
boolean_switch   = False
collection       = []
const_collection = []

λ python argparse_action.py -c

simple_value     = None
constant_value   = value-to-store
boolean_switch   = False
collection       = []
const_collection = []

λ python argparse_action.py -t

simple_value     = None
constant_value   = None
boolean_switch   = True
collection       = []
const_collection = []

λ python argparse_action.py -f

simple_value     = None
constant_value   = None
boolean_switch   = False
collection       = []
const_collection = []

λ python argparse_action.py -a one -a two -a three

simple_value     = None
constant_value   = None
boolean_switch   = False
collection       = ['one', 'two', 'three']
const_collection = []

λ python argparse_action.py -B -A

simple_value     = None
constant_value   = None
boolean_switch   = False
collection       = []
const_collection = ['value-2-to-append', 'value-1-to-append']
λ python argparse_action.py --version
argparse_action.py 1.0

解析器組

我們經常會遇到很多解析器都會需要相同的參數,例如都需要輸入用戶名密碼,這樣我們可以定義一個父解析器定義common的規則,子解析器可以集成,並且擴展。如果定義了相同的參數便會產生沖突。argparse有兩個內置的沖突處理器error(默認)和resolveresolve會基於沖突選項的添加順序來選擇一個參數處理器,后添加覆蓋老規則。我們應該盡量避免沖突,所以父解析器一般不定義幫助信息。下面舉個簡單的例子。

首先定義父解析器如下:

parser = argparse.ArgumentParser(description='parent 2', add_help=False)
parser.add_argument('-p', '--password', help='What is your passwrd')
parser.add_argument('-user', '--username', help='What is your username')
parser.add_argument('-m', '--female', help='What is your female')
args = parser.parse_args()
print(args)

# 結果
λ python arg_parent.py -h
usage: arg_parent.py [-p PASSWORD] [-user USERNAME] [-m FEMALE]
arg_parent.py: error: unrecognized arguments: -h

λ python arg_parent.py -p 123 -user ling -m man
Namespace(female='man', password='123', username='ling')

子解析器:集成並且重寫

import arg_parent

parser = argparse.ArgumentParser(description='son 1', parents=[arg_parent.parser], conflict_handler='resolve')
parser.add_argument('-w', '--weather', help="What's the weather")
parser.add_argument('-m', '--female', action='store_const', const='TRUE', help='What is your female')

args = parser.parse_args()
print(args)

# 結果
λ python arg_son.py -m -w cold -p 123
Namespace(female='TRUE', password='123', username=None, weather='cold')

λ python arg_son.py -m man
usage: arg_son.py [-h] [-p PASSWORD] [-user USERNAME] [-w WEATHER] [-m]
arg_son.py: error: unrecognized arguments: man

目前只用到了以上特性,還有一些特性就不一一介紹了,后續用到再補充。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM