Python学习——使用argparse模块传递脚本参数

冰冻三尺,非一日之寒

shell脚本一样,Python也可以实现脚本传参,其中一个比较简单的方式就是使用argparse模块来实现的。

基本使用格式
import argparse

parser = argparse.ArgumentParser()
parser.add_argument()
args = parser.parse_args()

首先导入argparse模块,然后构建创建一个对象来存储输入的参数,再通过add_argument()方法来添加参数,最后用parse_args()方法将parser对象进行解析。

PART1:ArgumentParser()

基本使用格式:

argparse.ArgumentParser(
    prog=None,
    usage=None,
    description=None,
    epilog=None,
    parents=[],
    formatter_class=,
    prefix_chars='-',
    fromfile_prefix_chars=None,
    argument_default=None,
    conflict_handler='error',
    add_help=True,
    allow_abbrev=True,
)
  • prog:程序名称,默认为sys.argv[0]
  • usage:使用方法,默认会从你的参数自动生成,可不指定。
  • description:程序描述性文档,该部分会显示使用方法帮助信息之间。
  • epilog:程序描述性文档,该部分会显示在参数描述之后。
  • parents:其它的parser对象,添加到这里就会自动在该程序中添加其中的参数。
  • formatter_class:打印帮助信息的风格(class)。
  • prefix_chars:可选参数前缀,默认是“ - ”。
  • argument_default:所有参数的默认值。
  • add_help:是否添加帮助信息,默认为True
下面进行详细的说明:
  • 首先说明前四个参数:
#!/usr/bin/python3

#test.py

import argparse

parser = argparse.ArgumentParser(prog = "test.py",
        description = "This is a test python script.",
        epilog = "This is an additional line.")
parser.add_argument("--print", "-p", type = str, default = "NONE", help = "str to print.")

args = parser.parse_args()
print(args.print)

在命令行中进行调用:

chmod +x test.py
./test.py --help
usage: test.py [-h] [--print PRINT]

This is a test python script.

optional arguments:
  -h, --help            show this help message and exit
  --print PRINT, -p PRINT
                        str to print.

This is an additional line.

可以看到:
(1)description参数的内容显示在使用方法和帮助信息之间;
(2)epilog参数的内容显示在参数描述之后;
(3)usage不需要你指定,会自动根据你的参数来进行组织。

  • 再说明parents参数:
    parents参数能够继承其它参数存储对象的内容,例如下面这段代码:
#!/usr/bin/python3

#test1.py

import argparse

parent_parser = argparse.ArgumentParser(add_help = False)
parent_parser.add_argument("--parentprint", "-t", type = str, default = "NONE", help = "str to print.")

parser = argparse.ArgumentParser(prog = "test.py",
        description = "This is a test python script.",
        epilog = "This is an additional line.",
        parents = [parent_parser])
parser.add_argument("--print", "-p", type = str, default = "NONE", help = "str to print.")

args = parser.parse_args()
print(args.print)

在命令行中调用:

./test1.py --help
usage: test.py [-h] [--parentprint PARENTPRINT] [--print PRINT]

This is a test python script.

optional arguments:
  -h, --help            show this help message and exit
  --parentprint PARENTPRINT, -t PARENTPRINT
                        str to print.
  --print PRINT, -p PRINT
                        str to print.

This is an additional line.

这里的--parentprint参数是由“父对象”parent_parser传递给“子对象”parser的。需要强调的是:parent_parser需要添加add_help=False参数,这是因为add_help默认为True,如果不设置,有关--help的信息会在结果中打印两遍。

  • 最后,解释一下formatter_class参数:
    具体来说,这个参数是控制帮助信息打印的格式,一般来说即使我们在descriptionepilog中进行换行,最终打印出来的信息还是会在一行中,那么formatter_class参数就能让你完全自定义打印的格式,例如下面这段代码:
#!/usr/bin/python3

#test2.py
import textwrap  #pay attention here
import argparse

parser = argparse.ArgumentParser(prog = "test.py",
        description =textwrap.dedent('''\
                This is a 
                test python script.
                '''),
        epilog = "This is an additional line.",
        formatter_class = argparse.RawDescriptionHelpFormatter)
parser.add_argument("--print", "-p", type = str, default = "NONE", help = "str to print.")

args = parser.parse_args()
print(args.print)

在命令行中调用:

./test2.py --help
usage: test.py [-h] [--print PRINT]

This is a 
test python script.

optional arguments:
  -h, --help            show this help message and exit
  --print PRINT, -p PRINT
                        str to print.

This is an additional line.

可以看到 This is a test python script 成功实现了换行。

formatter_class可选的取值:

  • argparse.RawDescriptionHelpFormatter
  • argparse.RawTextHelpFormatter
  • argparse.ArgumentDefaultsHelpFormatter
  • argparse.MetavarTypeHelpFormatter

argparse.RawDescriptionHelpFormatter能够同时控制descriptionepilog部分的格式,完全按照用户输入格式进行输出;argparse.RawTextHelpFormatter用于控制整个帮助文档的格式;argparse.ArgumentDefaultsHelpFormatter用于在每个选项参数的描述中添加默认值,即default值;argparse.MetavarTypeHelpFormatter用于在参数中添加type信息。

PART2:add_argument()

这个部分的内容一般会有:

  • (1)name or flag

该参数你可以简单理解为就是给传入的参数取了一个名字,可以是可选参数,也可以是位置参数,其中可选参数一般前面会有一个短横线“-”,这也是python识别可选参数的方法。
例如:创建可选参数的方法为parser.add_argument('-f', '--foo'),而位置参数则不需要短横线:parser.add_argument('bar')一般来说位置参数是必选的,什么是位置参数,可以简单理解为根据位置信息传入的参数,举一个最简单的例子:

#!/usr/bin/python

import argparse

parser = argparse.ArgumentParser()

parser.add_argument('bar')
args = parser.parse_args()

print(args.bar)

命令行调用:

./test.py --help
usage: test.py [-h] bar

positional arguments:
  bar

optional arguments:
  -h, --help  show this help message and exit
./test.py hello
hello
  • (2)action

当我们把参数读取进来了之后该怎么处理呢?这就是由action来决定的,action可能的取值有:storestore_conststore_truestore_falseappendappend_constcounthelpversionextend

逐个部分介绍,最后将会有一个综合实例进行解释:
~ store:这是默认操作,就是简单存储参数的值;
~ store_const:表示一旦有这个nameflag,则将其存储为某个定值,当action='store_const'时,就必须同时有const=的参数;
~ store_truestore_false:表示一旦有这个nameflag,则将其存储为布尔变量ture(对store_true来说)和false(对store_false来说),相应的没有这个nameflag时,则将其存储为布尔变量false(对store_true来说)和true(对store_false来说);
~ append:将传入的参数存储到列表当中,这个选项尤其适用于一个nameflag会出现多次的情况;
~ append_const:当有这个nameflag时,将其存储为定值并放在列表里;
~ count:计算一个nameflag出现的次数;
~ help:打印帮助信息的,默认添加了,不用管;
~ version:打印版本信息。

实例append_const后面再说):

#!/usr/bin/python

import argparse

parser = argparse.ArgumentParser(prog = 'test.py')

parser.add_argument('-a', action = 'store')
parser.add_argument('-b', action = 'store_const', const = 100)
parser.add_argument('-c', action = 'store_true')
parser.add_argument('-d', action = 'store_false')
parser.add_argument('-e', action = 'append')
parser.add_argument('-i', action = 'count')
parser.add_argument('-v', action = 'version', version='%(prog)s 1.0.0')

args = parser.parse_args()

print(args.a)
print(args.b)
print(args.c)
print(args.d)
print(args.e)
print(args.i)

下面来进行命令行调用,分别看输出结果:

./test.py -v
#test.py 1.0.0
./test.py -a store -b -c -d -e 1 -e 3 -iiii
#store  输入的就是'store'字符串,直接简单保存
#100  只要有'-b'这个name,就存储为一个定值const = 100
#True  只要有'-c'这个name,就存储为一个布尔变量True
#False  只要有'-d'这个name,就存储为一个布尔变量False
#['1', '3']  将通过'-e'传入的参数存储在列表中
#4  i出现了四次

再换种方式来调用:

./test.py
#None  没输入任何东西,所以是none
#None  没有'-b',所以时none
#False  没有'-c',所以是False
#True  没有'-d',所以是True
#None  没有'-e',所以是none
#None  没有-i,所以是none

当然你也可以通过default来指定默认的值,而不是None:

#!/usr/bin/python

import argparse

parser = argparse.ArgumentParser(prog = 'test.py')

parser.add_argument('-a', action = 'store', default = '***')
parser.add_argument('-b', action = 'store_const', const = 100)
parser.add_argument('-c', action = 'store_true')
parser.add_argument('-d', action = 'store_false')
parser.add_argument('-e', action = 'append')
parser.add_argument('-i', action = 'count', default = 10000)
parser.add_argument('-v', action = 'version', version='%(prog)s 1.0.0')

args = parser.parse_args()

print(args.a)
print(args.b)
print(args.c)
print(args.d)
print(args.e)
print(args.i)

调用:

./test.py
#***
#None
#False
#True
#None
#10000
  • (3)nargs

注意到我们前面的传参都是单个命令行参数,也就是说没有办法在一个nameflag后面传入两个及以上的参数,nargs正是为了解决这个问题。我们可以通过nargs来指定改nameflag后可传入的参数的个数,并将其存储在一个列表里面,即便只有一个参数(指定nargs = 1)。

#!/data01/skm/miniconda3/bin/python

import argparse

parser = argparse.ArgumentParser(prog = 'test.py')

parser.add_argument('-a', nargs = 2)
parser.add_argument('-b', nargs = 1)

args = parser.parse_args()

print(args.a)
print(args.b)

调用:

./test.py -a 1 2 -b c
#['1', '2']
#['d']

此外,有时我们会把nargs指定为?,而不是一个整数,这是因为有时候我们传入的参数可能只有一个也可能一个都没有,此时我们可以指定其为?,**需要解释的是,对于可选参数来说,我们可以同时添加constdefault:当没有nameflag时,会使用default的值;而当有nameflag而没有命令行参数时,就会使用const的值。

#!/usr/bin/python

import argparse

parser = argparse.ArgumentParser(prog = 'test.py')

parser.add_argument('-a', nargs = 2)
parser.add_argument('-b', nargs = 1)
parser.add_argument('-c', nargs = '?', default = 1, const = 2)

args = parser.parse_args()

print(args.a)
print(args.b)
print(args.c)

命令行调用:

./test.py -a 1 2 -b yes -c
#['1', '2']
#['yes']
#2

./test.py -a 1 2 -b yes
#['1', '2']
#['yes']
#1

./test.py -a 1 2 -b yes -c 3
#['1', '2']
#['yes']
#3

注意:不要认为?可以添加多个参数,实际上只能有一个或没有。

nargs还有*+两个可能的值,这主要适用于当我们有多个参数(大于3)需要传递时,会将参数存储在列表里面。

  • const

前面已经介绍,不再赘述。但是需要强调的是,使用const的情况只有两种:
(1)你的action类型为store_constappend_const
(2)指明了nargs='?'
否则你会收到报错。

  • default

以可选参数为例,如果对其添加了default,当你在调用程序不写该nameflag时,程序就会使用你的默认值:

#!/usr/bin/python

import argparse

parser = argparse.ArgumentParser(prog = 'test.py')

parser.add_argument('-a', default = 2)

args = parser.parse_args()

print(args.a)

命令行调用:

./test.py -a 3
#3
./test.py
#2
  • type

默认情况下,程序会认为你所传递的参数都是字符串。而有的时候你会需要诸如浮点数,整数等数据类型,这个时候你需要使用type来辅助程序确定你所输入的参数的数据类型:

parser.add_argument('-a', type = 'int')
parser.add_argument('-b', type = 'float')
  • choices

相较之于前面的完全自定义输入参数,有时你可能需要用户在你设置的可选列表里面选择合适的参数进行输入:

#!/usr/bin/python

import argparse

parser = argparse.ArgumentParser(prog = 'test.py')

parser.add_argument('-a', choices = [1, 2, 3])

args = parser.parse_args()

print(args.a)

命令行调用:

./test.py --help
#usage: test.py [-h] [-a {1,2,3}]

#optional arguments:
#  -h, --help  show this help message and exit
#  -a {1,2,3}
./test.py -a 4
#usage: test.py [-h] [-a {1,2,3}]
#test.py: error: argument -a: invalid choice: '4' (choose from 1, 2, 3)

可以看到我们必须在1,2,3中选择一个数来作为我们的输入才可以。

  • required

前面提到位置参数时必须的,而带有短横线的为可选参数,但我们常在编写python脚本时通常不会使用位置参数来作为必选参数,我们可以通过required=True来将其变为一个必选参数。

  • help

通过help可以为每个参数提供帮助描述信息,同时它也支持一些特殊化的显示,诸如%(prog)s%(default)s以及%(type)s等:

#!/usr/bin/python

import argparse

parser = argparse.ArgumentParser(prog = 'test.py')

parser.add_argument('-a', choices = [1, 2, 3], default = 1, help = 'the choices to %(prog)s. (default: %(default)s)')

args = parser.parse_args()

print(args.a)

命令行调用:

./test.py --help
#usage: test.py [-h] [-a {1,2,3}]

#optional arguments:
#  -h, --help  show this help message and exit
#  -a {1,2,3}  the choices to test.py. (default: 1)
  • metavar

注意到我们前面打印帮助信息时,每个参数后面都会有一串文字:

usage: test.py [-h] [-a AB]

optional arguments:
  -h, --help      show this help message and exit
  -a AB, --ab AB  the choices to test.py. (default: None)

例如这里的AB,而metavar就是用来自定义这部分文字的:

#!/usr/bin/python

import argparse

parser = argparse.ArgumentParser(prog = 'test.py')

parser.add_argument('-a', '--ab', help = 'the choices to %(prog)s. (default: %(default)s)', metavar = 'choice')

args = parser.parse_args()

print(args.a)

命令行调用:

./test.py --help
#usage: test.py [-h] [-a choice]

#optional arguments:
#  -h, --help            show this help message and exit
#  -a choice, --ab choice
#                        the choices to test.py. (default: None)

可以看到AB已经变成choice了。

  • dest

前面的示例当中我们最终取参数都是用的args.a这种形式,也就是和nameflag保持了一致。但是我们可以用dest来指定参数传入后的存储变量名称,这时就可以以append_const为例了:

#!/usr/bin/python

import argparse

parser = argparse.ArgumentParser(prog = 'test.py')

parser.add_argument('-a', const = 1, dest = 'choice', action = 'append_const')
parser.add_argument('-b', const = 2, dest = 'choice', action = "append_const")
args = parser.parse_args()

print(args.choice)

我们将-a-b传入的参数最终都存储在了choice变量里面,所以最终应该会产生如下结果:

./test.py -a -b
#[1, 2]
Reference: https://docs.python.org/3/library/argparse.html#

你可能感兴趣的:(Python学习——使用argparse模块传递脚本参数)