Python3 Argparse可选位置参数

时间:2017-10-25 15:44:12

标签: python-3.x argparse

目前,当我尝试在argparse中运行我的一个选项时,我必须先写一些东西,例如:

python3 main.py https://example.com ping-history

这对我的其他选项(ping和其他选项)很好,因为我需要指定我想要访问的网站。但是我需要它来为我的一个选项做一个例外。 所以它看起来像这样:

python3 main.py ping-history

我尝试添加:

nargs="?"

为:

parser.add_argument('filename', help="input file") 

这解决了这个问题,但是当我尝试运行--verbose或--silent:

python3 main.py https://example.com -v title

我明白了:

main.py: error: argument commands: invalid choice: 'https://example.com'

我不确定发生了什么,有人可以解释一下吗?

编辑:解析器文件:

import argparse


VERSION = "v1.0.0 (2017-06-16)"



def add_options(parser):
    """add options"""
    group = parser.add_mutually_exclusive_group()
    group.add_argument("-s", "--silent", dest="silent", help="Less output", action="store_true")
    group.add_argument("-v", "--verbose", dest="verbose", help="More output", action="store_true")
    parser.add_argument("-V", "--version", action="version", version=VERSION)
    parser.add_argument('filename', help="input file", nargs="?")


def add_commands(parser):
    """Adds commands"""
    subparser = parser.add_subparsers(title="commands  (positional arguments)", help="Available commands",\
    dest="commands")

    subparser.add_parser("lines", help="count lines in textfile")
    subparser.add_parser("words", help="count words in textfile")
    subparser.add_parser("letters", help="count letters in textfile")
    subparser.add_parser("all", help="count all")
    subparser.add_parser("word_frequency", help="count word frequency")
    subparser.add_parser("letter_frequency", help="count letter frequency")
    #subparser.add_parser("filename", help= "filename to analyze")
    subparser.add_parser("ping", help="ping a website")
    subparser.add_parser("ping-history", help="show past status code")
    subparser.add_parser("quote", help="retrieve todays quote")
    subparser.add_parser("title", help="retrive titel from page")


def parse_options():
    """add options"""

    parser = argparse.ArgumentParser()
    add_options(parser)
    add_commands(parser)


    arg, unknown_args = parser.parse_known_args()

    options = {}
    options["known_args"] = vars(arg)
    options["unknown_args"] = unknown_args




    return options

1 个答案:

答案 0 :(得分:1)

在我的评论中,我猜到你有一个可选的位置。但进一步认为你的错误更符合初始的可选位置。

In [42]: parser=argparse.ArgumentParser()
In [43]: a1 = parser.add_argument('name');
In [44]: parser.add_argument('-v',action='store_true');
In [45]: parser.add_argument('cmds',choices=['one','two'])

In [46]: parser.parse_args('foo one'.split())
Out[46]: Namespace(cmds='one', name='foo', v=False)
In [47]: parser.parse_args('foo -v one'.split())
Out[47]: Namespace(cmds='one', name='foo', v=True)

将第一个参数更改为可选:

In [48]: a1.nargs
In [49]: a1.nargs='?'

In [50]: parser.parse_args('foo one'.split())
Out[50]: Namespace(cmds='one', name='foo', v=False)

In [51]: parser.parse_args('foo -v one'.split())
usage: ipython3 [-h] [-v] [name] {one,two}
ipython3: error: argument cmds: invalid choice: 'foo' (choose from 'one', 'two')
...

如果我只给它一个字符串,我会得到同样的错误:

In [54]: parser.parse_args('foo'.split())
usage: ipython3 [-h] [-v] [name] {one,two}
ipython3: error: argument cmds: invalid choice: 'foo'

parse_args在评估位置和选项之间交替。在做位置时,它会尝试处理尽可能多的字符串(使用regex样式模式匹配)。一个 '?' position可以匹配一个空字符串。因此,当它只看到一个字符串'foo'时,它会将[]与'name'匹配,并尝试将'foo'与'cmd'匹配。

有关于使解析看起来更进一步的错误/问题,并预期第二个位置可能会满足标志后的字符串。但是现在,当一个或多个位置是“可选的”时,不要混合使用标志和位置。

In [55]: parser.parse_args('foo one -v'.split())
Out[55]: Namespace(cmds='one', name='foo', v=True)
In [56]: parser.parse_args('-v foo one'.split())
Out[56]: Namespace(cmds='one', name='foo', v=True)

修改

在完整的解析器中,第二个positional是subparser。如上所述,它会尝试将['https://example.com']应用于'?'论证和subparser。

所以工作电话是:

python3 main.py -v https://example.com title

如果只有部分commands需要filename,请考虑将该参数分配给这些子分析器,而不是将其作为父分析器的可选参数。

一般来说,使用subparser时父母的位置很棘手。标记所有父参数会更容易。