关于python:简单argparse示例需要:1个参数,3个结果

Simple argparse example wanted: 1 argument, 3 results

argparse python模块的文档虽然很好,但我确信,对于我的初学者来说,现在太多了,我无法理解。我不需要在命令行上做数学运算,也不需要干预屏幕上的格式化行或更改选项字符。我所要做的就是"如果arg是a,那么做这个,如果b做那个,如果上面没有显示帮助并退出"。


以下是我使用argparse的方法(使用多个参数):

1
2
3
4
parser = argparse.ArgumentParser(description='Description of your program')
parser.add_argument('-f','--foo', help='Description for foo argument', required=True)
parser.add_argument('-b','--bar', help='Description for bar argument', required=True)
args = vars(parser.parse_args())

args将是一个包含以下参数的字典:

1
2
3
4
5
if args['foo'] == 'Hello':
    # code here

if args['bar'] == 'World':
    # code here

在您的情况下,只需添加一个参数。


我对原始问题的理解是双重的。首先,对于最简单的argparse示例,我很惊讶在这里没有看到它。当然,简单地说,这也是所有的开销和小功率,但它可能会让你开始。

1
2
3
4
5
6
7
8
import argparse

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

if args.a == 'magic.name':
    print 'You nailed it!'

但是这个位置参数现在是必需的。如果您在调用这个程序时忽略了它,您将得到一个关于缺少参数的错误。这就引出了最初问题的第二部分。MattWilkie似乎想要一个没有命名标签(选项标签)的可选参数。我的建议是将上述代码修改如下:

1
2
3
4
5
6
7
8
9
...
parser.add_argument("a", nargs='?', default="check_string_for_empty")
...
if args.a == 'check_string_for_empty':
    print 'I can tell that no argument was given and I can deal with that here.'
elif args.a == 'magic.name':
    print 'You nailed it!'
else:
    print args.a

可能会有一个更优雅的解决方案,但这是可行的,而且是极简主义的。


argparse文档相当好,但遗漏了一些可能不明显的有用细节。(@diego navarro已经提到了其中的一些内容,但我将尝试稍微扩展一下他的答案。)基本用法如下:

1
2
3
4
parser = argparse.ArgumentParser()
parser.add_argument('-f', '--my-foo', default='foobar')
parser.add_argument('-b', '--bar-value', default=3.14)
args = parser.parse_args()

parse_args()返回的对象是一个"名称空间"对象:其成员变量以命令行参数命名的对象。Namespace对象是访问参数及其相关值的方式:

1
2
3
args = parser.parse_args()
print args.my_foo
print args.bar_value

(请注意,命名变量时,argparse将参数名中的"-"替换为下划线。)

在许多情况下,您可能希望将参数简单地用作不带值的标志。您可以这样在argparse中添加这些内容:

1
2
parser.add_argument('--foo', action='store_true')
parser.add_argument('--no-foo', action='store_false')

上面将分别创建名为"foo"且值为true和"no foo"且值为false的变量:

1
2
3
4
5
if (args.foo):
    print"foo is true"

if (args.no_foo is False):
    print"nofoo is false"

还请注意,添加参数时可以使用"必需"选项:

1
parser.add_argument('-o', '--output', required=True)

这样,如果您在命令行argparse中忽略了这个参数,就会告诉您它丢失了,并停止执行脚本。

最后,请注意,如果使用vars函数使您的生活更容易,那么可以使用该函数创建您的论点的dict结构。

1
2
3
4
args = parser.parse_args()
argsdict = vars(args)
print argsdict['my_foo']
print argsdict['bar_value']

如您所见,vars返回一个dict,其中参数名作为键,其值为,er,值。

有许多其他选项和您可以做的事情,但这应该涵盖最基本的、最常见的使用场景。


Matt询问argparse中的位置参数,我同意在这方面缺少Python文档。在20多个页面中没有一个完整的示例可以同时显示解析和使用位置参数。

这里的其他答案都没有显示位置参数的完整示例,因此这里是一个完整的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# tested with python 2.7.1
import argparse

parser = argparse.ArgumentParser(description="An argparse example")

parser.add_argument('action', help='The action to take (e.g. install, remove, etc.)')
parser.add_argument('foo-bar', help='Hyphens are cumbersome in positional arguments')

args = parser.parse_args()

if args.action =="install":
    print("You asked for installation")
else:
    print("You asked for something other than installation")

# The following do not work:
# print(args.foo-bar)
# print(args.foo_bar)

# But this works:
print(getattr(args, 'foo-bar'))

令我不快的是,argparse将把命名的参数--foo bar"转换为"foo bar",但是名为"foo bar"的位置参数保持为"foo bar",这使得如何在程序中使用它变得不那么明显。

注意我的示例末尾附近的两行——这两行都不能得到foo bar位置参数的值。第一个显然是错误的(它是一个算术表达式args.foo减去bar),但第二个也不起作用:

1
AttributeError: 'Namespace' object has no attribute 'foo_bar'

如果要使用foo-bar属性,则必须使用getattr,如我示例的最后一行所示。疯狂的是,如果您试图使用dest=foo_bar将属性名称更改为更容易访问的名称,您会收到一条非常奇怪的错误消息:

1
ValueError: dest supplied twice for positional argument

下面是上面的示例的运行方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ python test.py
usage: test.py [-h] action foo-bar
test.py: error: too few arguments

$ python test.py -h
usage: test.py [-h] action foo-bar

An argparse example

positional arguments:
  action      The action to take (e.g. install, remove, etc.)
  foo-bar     Hyphens are cumbersome in positional arguments

optional arguments:
  -h, --help  show this help message and exit

$ python test.py install foo
You asked for installation
foo


另一个概要介绍,受本文启发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import argparse

# define functions, classes, etc.

# executes when your script is called from the command-line
if __name__ =="__main__":

    parser = argparse.ArgumentParser()
    #
    # define each option with: parser.add_argument
    #
    args = parser.parse_args() # automatically looks at sys.argv
    #
    # access results with: args.argumentName
    #

参数由以下组合定义:

1
2
3
parser.add_argument( 'name', options... )              # positional argument
parser.add_argument( '-x', options... )                # single-char flag
parser.add_argument( '-x', '--long-name', options... ) # flag with long name

常见的选项有:

  • 帮助:使用--help时此参数的说明。
  • 默认值:省略参数时的默认值。
  • 类型:如果您希望使用floatint(否则为str)。
  • dest:给一个旗子取一个不同的名字(如'-x', '--long-name', dest='longName')。注:默认情况下,--long-name通过args.long_name访问。
  • 操作:用于特殊处理某些参数
    • store_true, store_false:用于布尔型参数'--foo', action='store_true' => args.foo == True
    • store_const:与选项const'--foo', action='store_const', const=42 => args.foo == 42一起使用。
    • count:重复期权,如./myscript.py -vv'-v', action='count' => args.v == 2所述。
    • append:重复期权,如./myscript.py --foo 1 --foo 2'--foo', action='append' => args.foo == ['1', '2']所述。
  • 必需:如果需要标志,或者位置参数不是。
  • n args:用于捕获n个args ./myscript.py --foo a b => args.foo = ['a', 'b']
  • 选择:限制可能的输入(指定为字符串列表,或者如果是type=int)。

以下是我在学习项目中的想法,主要归功于@dmh…

演示代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import argparse

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-f', '--flag', action='store_true', default=False)  # can 'store_false' for no-xxx flags
    parser.add_argument('-r', '--reqd', required=True)
    parser.add_argument('-o', '--opt', default='fallback')
    parser.add_argument('arg', nargs='*') # use '+' for 1 or more args (instead of 0 or more)
    parsed = parser.parse_args()
    # NOTE: args with '-' have it replaced with '_'
    print('Result:',  vars(parsed))
    print('parsed.reqd:', parsed.reqd)

if __name__ =="__main__":
    main()

这可能已经发展,可以在线使用:command-line.py

为代码提供训练的脚本:command-line-demo.sh


请注意python howtos中的argparse教程。它从最基本的例子开始,比如这个例子:

1
2
3
4
5
6
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
                    help="display a square of a given number")
args = parser.parse_args()
print(args.square**2)

然后发展到不太基本的。

有一个选项的预定义选项示例,如所要求的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
                    help="display a square of a given number")
parser.add_argument("-v","--verbosity", type=int, choices=[0, 1, 2],
                    help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
if args.verbosity == 2:
    print("the square of {} equals {}".format(args.square, answer))
elif args.verbosity == 1:
    print("{}^2 == {}".format(args.square, answer))
else:
    print(answer)


您也可以使用plac(一个围绕argparse的包装)。

作为奖励,它生成了简洁的帮助说明-见下文。

示例脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python3
def main(
    arg: ('Argument with two possible values', 'positional', None, None, ['A', 'B'])
):
   """General help for application"""
    if arg == 'A':
        print("Argument has value A")
    elif arg == 'B':
        print("Argument has value B")

if __name__ == '__main__':
    import plac
    plac.call(main)

实例输出:

未提供参数-example.py

1
2
usage: example.py [-h] {A,B}
example.py: error: the following arguments are required: arg

提供了意外的参数-example.py C

1
2
usage: example.py [-h] {A,B}
example.py: error: argument arg: invalid choice: 'C' (choose from 'A', 'B')

提供了正确的参数-example.py A

1
Argument has value A

全帮助菜单(自动生成)-example.py -h

1
2
3
4
5
6
7
8
9
usage: example.py [-h] {A,B}

General help for application

positional arguments:
  {A,B}       Argument with two possible values

optional arguments:
  -h, --help  show this help message and exit

简短说明:

参数名通常等于参数名(arg)。

arg参数后的tuple注释具有以下含义:

  • 说明(Argument with two possible values)
  • 参数类型-"flag"、"option"或"positional"之一(positional)
  • 缩写(None)
  • 参数值类型-例如float、string(None)
  • 限制选择集(['A', 'B'])

文档:

要了解更多关于使用plac的信息,请查看其重要文档:

Plac: Parsing the Command Line the Easy Way


加上其他人的陈述:

我通常喜欢使用"dest"参数指定变量名,然后使用"globals().update()"将这些变量放入全局命名空间。

用途:

1
$ python script.py -i"Hello, World!"

代码:

1
2
3
4
5
...
parser.add_argument('-i', '--input', ..., dest='inputted_variable',...)
globals().update(vars(parser.parse_args()))
...
print(inputted_variable) # Prints"Hello, World!"