1. 程式人生 > >使用Python中的argparse從命令列接收boolean型別的引數

使用Python中的argparse從命令列接收boolean型別的引數

Python程式從命令列讀取引數

很多時候,為了使我們所寫的程式更加靈活,我們會給這個程式加上在命令列中呼叫時可以指定引數的功能。Python中argparse就是一個方便使用的讀取命令列引數的庫。使用argparse讀取在命令列呼叫程式時指定的引數的示例程式碼如下:

import argparse

if __name__ == '__main__':
    parser = argparse.ArgumentParser()

    parser.add_argument(
        'positional_argument',
        help='this is a positional argument'
, ) parser.add_argument( '--arg1', help='the first argument', type=int, dest='arg1', default=1, ) parser.add_argument( '--arg2', help='the second argument', type=str, dest='arg2', ) args = parser.parse_args() pos_argument = args.positional_argument arg1 = args.arg1 arg2 = args.arg2

接下來在呼叫這個程式的時候,我們只需要使用如下命令即可將相應的positional argument和keyword argument傳入程式中:

python out_program.py positional_argument --arg1 0 --arg2 argument

如果我們想要指定一個boolean型別的argument作為某種flag使用呢?

雖然argparse用起來非常方便,然而遺憾的是其在處理boolean型別的引數的時候並不能自動轉換引數型別。也就是說,對於如下這種引數:

parser = argparse.ArgumentParser()
parser
.add_argument( '--bool-arg', help='this is a True or False we want', dest='bool_arg', type=bool, ) args = parser.parse_args() my_bool = args.bool_arg

雖然我們指定了其型別為bool,但無論我們在命令列中給這個引數傳入什麼值(如True,False等),my_bool的值總是為True。

那麼我們究竟應該如何從命令列中接收一個能夠返回boolean型別值的引數呢?

有如下三種方法:

分別使用不同的引數標識我們需要的flag

flag_parser = parser.add_mutually_exclusive_group(required=False)
flag_parser.add_argument('--flag', dest='flag', action='store_true')
flag_parser.add_argument('--no-flag', dest='flag', action='store_false')
parser.set_defaults(flag=True)

然後我們就可以使用python command --flag或者python command --no-flag來指定flag的值了。注意這裡我們使用了parser.add_mutually_exclusive_group來指定這兩個引數為互斥引數。這樣我們就可以保證二者只有一個能夠被指定。python command --flag --no-flag會報錯。

定義一個函式作為傳入typecallable幫我們進行型別轉換

add_argument所接收的一個callable型別的type引數可以幫我們對收到的原始引數進行處理。所以我們可以定義一個函式作為type幫我們進行預處理。比如如下例子:

def str2bool(v):
    if v.lower() in ('yes', 'true', 't', 'y', '1'):
        return True
    elif v.lower() in ('no', 'false', 'f', 'n', '0'):
        return False
    else:
        raise argparse.ArgumentTypeError('Unsupported value encountered.')

parser.add_argument(
    '--flag',
    type=str2bool,
    nargs='?',
    const=True,
    help='Turn on or turn off flag'
)

當我們使用上面這個例子的時候,程式可以這樣呼叫:

python command --flag # 使用const中指定的值作為引數值
python command --flag 0

使用ast.literal_eval作為type

下面是ast.literal_eval的文件:

Safely evaluate an expression node or a Unicode or Latin-1 encoded string containing a Python literal or container display. The string or node provided may only consist of the following Python literal structures: strings, numbers, tuples, lists, dicts, booleans, and None.
This can be used for safely evaluating strings containing Python values from untrusted sources without the need to parse the values oneself. It is not capable of evaluating arbitrarily complex expressions, for example involving operators or indexing.

可以得知,ast.literal_eval可以從字串中讀取Python的string, numbers, tuples, lists, dicts, booleans and None型別的物件。所以我們只需指定當前argument的type為ast.literal_eval,就可以得到boolean型別的值了。但這種方法的問題在於,只有當引數輸入為'False'時讀取的值才為False,否則為True。如下面的例子所示:

parser.add_argument(
    '--flag',
    help='True or False flag, input should be either "True" or "False".',
    type=ast.literal_eval,
    dest='flag',
)

呼叫方法為:

python command --flag True
python command --flag False