python命令行参数解析模块argparse和docopt

时间:2023-03-09 02:54:14
python命令行参数解析模块argparse和docopt

http://blog.csdn.net/pipisorry/article/details/53046471

还有其他两个模块实现这一功能,getopt(等同于C语言中的getopt())和弃用的optparse。因为argparse是基于optparse,所以用法很类似。

参数解析模块argparse

添加命令行解析参数add_argument()方法

参数可以触发不同的动作,动作由 add_argument() 方法的 action 参数指定。支持的动作包括保存参数(逐个地,或者作为列表的一部分),当解析到某参数时保存一个常量值(包括对布尔开关真/假值的特殊处理),统计某个参数出现的次数,以及调用一个回调函数。

默认的动作是保存参数值。在这种情况下,如果提供一个类型,那么在存储之前会先把该参数值转换成该类型。如果提供 dest 参数,参数值就保存为命令行参数解析时返回的命名空间对象中名为该 dest 参数值的一个属性。

add_argument参数

ArgumentParser.add_argument(name or flags...[, action][, nargs][, const][, default][, type][, choices][, required][, help][, metavar][, dest])

Define how a single command-line argument should be parsed. Each parameterhas its own more detailed description below, but in short they are:

  • name or flags - Either a name or a list of option strings, e.g. fooor -f, --foo.
  • action - The basic type of action to be taken when this argument isencountered at the command line.
  • nargs - The number of command-line arguments that should be consumed.
  • const - A constant value required by some action and nargs selections.
  • default - The value produced if the argument is absent from thecommand line.对于可选参数,default的值用于选项字符串没有出现在命令行中的时候。
  • type - The type to which the command-line argument should be converted.
  • choices - A container of the allowable values for the argument.
  • required - Whether or not the command-line option may be omitted(optionals only).
  • help - A brief description of what the argument does.
  • metavar - A name for the argument in usage messages.
  • dest - The name of the attribute to be added to the object returned byparse_args().

[add_argument() method]

参数动作action

argparse内置6种动作可以在解析到一个参数时进行触发:

store 保存参数值,可能会先将参数值转换成另一个数据类型。若没有显式指定动作,则默认为该动作。默认action模式,存储值到指定变量。

store_const 保存一个被定义为参数规格一部分的值,而不是一个来自参数解析而来的值。这通常用于实现非布尔值的命令行标记。lz:使用const='value-to-store',来人保存默认值(如果没有指定值的话)?

store_ture/store_false 保存相应的布尔值。这两个动作被用于实现布尔开关。lz:store_ture/:如果这个参数存在则默认为True,不管default = 什么。

append 将值保存到一个列表中。若参数重复出现,则保存多个值。存储值到列表,该参数可以重复使用。

append_const 将一个定义在参数规格中的值保存到一个列表中。设不设置default=[]好像没影响。也是使用const='value-2-to-append',添加默认值。

version 打印关于程序的版本信息,然后退出

小示例

以下简单示例带有3个不同的选项:一个布尔选项(-a),一个简单的字符串选项(-b),以及一个整数选项(-c)。

import argparse

parser = argparse.ArgumentParser(description='Short sample app')

parser.add_argument('-a', action="store_true", default=False)
parser.add_argument('-b', action="store", dest="b")
parser.add_argument('-c', action="store", dest="c", type=int)

print parser.parse_args(['-a', '-bval', '-c', '3'])

有几种方式传递值给单字符选项。以上例子使用了两种不同的形式,-bval-c val

$ python argparse_short.py
Namespace(a=True, b='val', c=3)

可变形参列表nargs

你可以配置单个参数的定义使其能够匹配所解析的命令行的多个参数。根据需要或期望的参数个数,设置nargs为这些标识值之一:

值  含义
N   参数的绝对个数(例如:3)
?   0或1个参数
*   0或所有参数
+   所有,并且至少一个参数

parser.add_argument('--all', nargs='*', dest='all')

parser.add_argument('-o', nargs=3)

绝对个数不能是字符串'3',否则报错:ValueError: length of metavar tuple does not match nargs

参数类型type

argparse将所有参数值都看作是字符串,除非你告诉它将字符串转换成另一种数据类型。add_argument()的type参数以一个转换函数作为值,被ArgumentParser用来将参数值从一个字符串转换成另一种数据类型。

参数类型type:如果不指定参数类型,argparse默认它是字符串。

parser.add_argument('--file', type=file)
try:
    print parser.parse_args()
except IOError, msg:
    parser.error(str(msg))

文件参数

虽然文件对象可以单个字符串参数值来实例化,但并不允许你指定访问模式。FileType让你能够更加灵活地指定某个参数应该是个文件,包括其访问模式和缓冲区大小。

parser.add_argument('-i', metavar='in-file', type=argparse.FileType('rt'))
parser.add_argument('-o', metavar='out-file', type=argparse.FileType('wt'))

try:
    results = parser.parse_args()
    print 'Input file:', results.i
    print 'Output file:', results.o
except IOError, msg:
    parser.error(str(msg))

参数预定义值choice

将一个输入参数限制为一个预定义集中的某个值,则使用choices参数。

parser.add_argument('--mode', choices=('read-only', 'read-write'))
如果--mode的参数值不是所允许的值中的一个,就会产生一个错误并停止执行。

自动生成选项-h -v

经过配置argparse会自动添加选项用来生成帮助信息以及为你的应用程序显示版本信息。
ArgumentParser的参数add_help 控制帮助信息相关的选项。
parser = argparse.ArgumentParser(add_help=True)
帮助选项(-h和--help)默认是添加的,但可以通过将add_help设置为false来禁用。
虽然-h和--help是事实上的请求帮助的标准选项名称,但一些应用或argparse的使用要么不需要提供帮助要么需要将这两个选项名称用于其他目标。

当在ArgumentParser构造方法设置版本后,就会添加版本选项(-v和--version)。
parser = argparse.ArgumentParser(version='1.0')
两种形式的选项爱那个都会打印程序的版本字符串,然后立即退出程序。

自定义动作

除了前面描述的内置动作之外,你也可以提供一个实现了Action API的对象来自定义动作。作为action传递给add_argument()的对象应接受描述所定义形参的实参,并返回一个可调用对象,作为parser的实参来处理形参,namespace存放解析的结果、参数值,以及触发动作的option_string。
argparse提供了一个Action类作为要定义的新动作的基类。构造方法是处理参数定义的,所以你只要在子类中覆盖call()。

自定义action是argparse.Action的子类可以处理add_argument中的参数定义相关的参数,并返回一个可调用对象。构造函数会处理参数定义,仅仅需要处理__call__函数。__call__函数中parser代表解释器,namespace用于返回解释结果,value为要处理的参数,option_string用于触发action(对可选参数,永远是None。

非选项参数值的处理

argparse区别于optparse的一个地方是对非选项参数值的处理。optparse只进行选项解析,而argparse是一个全面的命令行参数解析工具,也处理非选项参数。

import argparse

parser = argparse.ArgumentParser(description='Example with non-optional arguments')

parser.add_argument('count', action="store", type=int)
parser.add_argument('units', action="store")

print parser.parse_args()

在这个例子中,“count”参数是一个整数,“units”参数存储为一个字符串。其中任意一个参数若没有在命令行中提供,或给定的值不能被转换为正确的类型,就会报告一个错误。

$ python argparse_arguments.py 3 inches
Namespace(count=3, units='inches')

解析器组

共享解析器规则
冲突的选项
参数群组
互斥选项
嵌套解析器

。。。

皮皮blog

ArgumentParser对象

选项前缀prefix_chars

argparse选项的默认语法是基于Unix约定的,使用一个“-”前缀来表示命令行开关。argparse支持其他前缀,因此你可以使得你的程序遵照本地平台的默认语法(例如,在Window上使用“/”)或者遵循不同的约定。

将ArgumentParser 方法的prefix_chars 参数设置为一个字符串,该字符串包含所有允许用来表示选项的字符。需要理解的是虽然prefix_chars包含允许用于开关的字符,但单个参数定义只能使用一种给定的开关语法。这让你可以对使用不同前缀的选项是否是别名(比如独立于平台的命令行语法的情况)或替代选择(例如,使用“+”表明打开一个开发,“-”则为关闭一个开关)进行显式地控制。在上述例子中,+a和-a是不同的参数,//noarg 也可以 ++noarg 提供,但不是 --noarg。

parser = argparse.ArgumentParser(description='Change the option prefix charaters', prefix_chars='-+/')

argparse异常处理

argparse出错异常时总是输出,而有时我们只需要不出现异常的解析结果,异常的直接丢掉。这时我们可以自定义一个error输出。

parser.error = lambda errmsg: exec('raise(Exception(errmsg))')

再在外层处理

try:
:]))
except Exception as  e:
    # print('{} has invalid args!!!\n{}\n'.format(s, traceback.format_exc()))
    print('{} has invalid args!!!\n{}\n'.format(s, e))
    return

[Python argparse and controlling/overriding the exit status code]

[I want Python argparse to throw an exception rather than usage]

[ArgumentParser objects]

皮皮blog

parse_args()方法

解析一个命令行参数来源parse_args()

定义了所有参数之后,你就可以给 parse_args() 传递一组参数字符串来解析命令行。默认情况下,参数是从 sys.argv[1:] 中获取,但你也可以传递自己的参数列表。选项是使用GNU/POSIX语法来处理的,所以在序列中选项和参数值可以混合。parse_args() 的返回值是一个命名空间,包含传递给命令的参数。该对象将参数保存其属性,因此如果你的参数 dest 是 "myoption",那么你就可以args.myoption 来访问该值。

目前为止所见的例子中,提供给解析器的参数列表来自于显式传递的一个列表,或隐式地从sys.argv获取的。显式传递列表在你使用argparse来处理类命令行但并不是来自命令行(比如来自一个配置文件)的指令之时比较有用。

1

import shlex

argument_list = shlex.split(config_value)
print 'Results:', parser.parse_args(argument_list)

2

另一种自己处理配置文件的方法是使用fromfile_prefix_chars指定一个包含一组要待处理参数的输入文件来告诉argparse怎样识别参数。
import argparse
from ConfigParser import ConfigParser
import shlex

parser = argparse.ArgumentParser(description='Short sample app',  fromfile_prefix_chars='@')

parser.add_argument('-a', action="store_true", default=False)
parser.add_argument('-b', action="store", dest="b")
parser.add_argument('-c', action="store", dest="c", type=int)
print parser.parse_args(['@argparse_fromfile_prefix_chars.txt'])
该示例代码在找到一个以@为前缀的参数时即停止往下读取,然后从以该参数命名的文件中查找更多的参数。...

[The parse_args() method]

皮皮blog

使用示例

示例1

def t():
    import argparse

    parser = argparse.ArgumentParser()
    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='t', help='Set a switch to true')
    parser.add_argument('-f', action='store_false', default=False, dest='f', 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',
                        help='Add different values to list')
    parser.add_argument('-B', action='append_const', dest='const_collection', const='value-2-to-append',default=[],
                        help='Add different values to list')
    parser.add_argument('--version', action='version', version='%(prog)s 1.0')

    # results = parser.parse_args('-a dk -a di -f -B -A'.split())
    results = parser.parse_args()
    print('simple_value     =', results.simple_value)
    print('constant_value   =', results.constant_value)
    print('t   =', results.t)
    print('f   =', results.f)
    print('collection       =', results.collection)
    print('const_collection =', results.const_collection)

$ python argparse_action.py -h
usage: argparse_action.py [-h] [-s SIMPLE_VALUE] [-c] [-t] [-f]
                          [-a COLLECTION] [-A] [-B] [--version]
optional arguments:
  -h, --help       show this help message and exit
  -s SIMPLE_VALUE  Store a simple value
  -c               Store a constant value
  -t               Set a switch to true
  -f               Set a switch to false
  -a COLLECTION    Add repeated values to a list
  -A               Add different values to list
  -B               Add different values to list
  --version        show program's version number and exit

$ 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']

示例2:解析参数并修改,不符合的删除(代码非最优)

origin_strs = [
    '#/bin/clang -g  -DUNDEF_THREADS_HACK -c -o chared_err.o chared.c',
    '#/bin/clang -g  -DUNDEF_THREADS_HACK -c -o aa chared_err.o chared.c']

def argparse_test(s):
    import argparse, re, os, traceback
    dir = 'path'

    parser = argparse.ArgumentParser(description='Process clang args')
    parser.error = lambda errmsg: exec('raise(Exception(errmsg))')

    parameters = ['-g', '-DUNDEF_THREADS_HACK', '-c', '-o']
    parser.add_argument(parameters[], ], action='store_true', required=True)
    parser.add_argument(parameters[], ], action='store_true', required=True)
    parser.add_argument(parameters[], ], action='store_true', required=True)
    parser.add_argument(parameters[], ], )

    try:
:]))
    except Exception as  e:
        # print('{} has invalid args!!!\n{}\n'.format(s, traceback.format_exc()))
        print('{} has invalid args!!!\n{}\n'.format(s, e))
        return
]
    for p in parameters:
        if args.get(p):
            if type(args.get(p)) is list:
                args[p] = ' '.join(args.get(p))
            if p is '-c':
                args[p] = ' -emit-llvm -c'
            elif p is '-o':
                args[p] = ' -o ' + re.sub('(\w+\.o)', os.path.join(dir, r'\1') + '.bc', args[p])
            else:
                args[p] = ' '.join([p, args.get(p)]) if type(args.get(p)) is not bool else ' ' + p
            new_str += args.get(p)

    print("{} \n ====> \n {}\n".format(s, new_str))

for s in origin_strs:
    argparse_test(s)

皮皮blog

参数解析模块docopt

Pythonic的命令行参数解析库。 docopt : Pythonic command line arguments parser, that will make you smile. docopt,替代argparse,简洁明快。最关键的是它的思路完全不同。Github: https://github.com/docopt/docopt

用过doctest? 那来看看docopt。有时候你用py写一个命令行程序,需要接收命令行参数,看看这个例子:

"""
Usage: test.py <file> [--verbose]
"""
from docopt import docopt
print docopt(__doc__)

如果你这么执行程序 python test.py somefile --verbose

你会得到这样的输出 {'--verbose': True, '<file>': 'somefile'}

"""Usage:
  quick_example.py tcp <host> <port> [--timeout=<seconds>]
  quick_example.py serial <port> [--baud=9600] [--timeout=<seconds>]
  quick_example.py -h | --help | --version

"""

[英文文档docopt Command-line interface description language]

皮皮blog

clize

用 docopt 写程序的使用doc是不是很爽, clize是一个类似的库。可以用程序的函数名字来作为使用方法

#!/usr/bin/env python

from clize import clize

@clize
def echo(text, reverse=false):
    if reverse:
        text = text[::-1]
    print(text)
if __name__ == '__main__':
    import sys
    echo(*sys.argv)

而这个小程序就可以这么使用:

$ ./echo.py --help
Usage: ./echo.py [OPTIONS] text

Positional arguments:
  text

Options:
  --reverse
  -h, --help   Show this help

[https://github.com/epsy/clize]

from: http://blog.csdn.net/pipisorry/article/details/53046471

ref: [argparse — Parser for command-line options, arguments and sub-commands]

[Argparse简易教程译自Argparse Tutorial]

[argparse - 命令行选项与参数解析(译)*]