25

我试图让 argparse 忽略这样一个事实,即在指定可选参数 ( ) 时不应评估两个通常需要的位置参数-l

基本上我试图复制 --help 的行为:当您指定 -h 时,所有缺少的必需参数都将被忽略。

示例代码:

parser = argparse.ArgumentParser(description="Foo bar baz")
parser.add_argument('arg1', help='arg1 is a positional argument that does this')
parser.add_argument('arg2', help='arg2 is a positional argument that does this')
parser.add_argument('-l', '--list', dest='list', help='this is an optional argument that prints stuff')

options, args = parser.parse_args()

if options.list:
   print "I list stuff"

当然,如果我现在运行它,我会得到:

error: too few arguments

我尝试了不同的东西,例如nargs='?',但没有任何工作。

这个问题非常相似,但没有得到回答。

4

6 回答 6

9

不幸的是,argparse这还不够灵活。您可以做的最好的事情是制作arg1arg2可选使用nargs="?"并检查自己是否在需要时提供它们。

内部help操作是通过打印帮助消息并在命令行上遇到-h或遇到时立即退出程序来实现的。--help你可以自己写一个类似的动作,比如

class MyAction(argparse.Action):
    def __call__(self, parser, values, namespace, option_string):
        print "Whatever"
        parser.exit()

(警告:未经测试的代码!)

不过,后一种方法有明显的缺点。帮助信息将无条件地显示arg1arg2强制参数。当遇到-lor时,解析命令行就会停止--list,忽略任何进一步的参数。这种行为对于 是完全可以接受的--help,但对于其他选项来说不太理想。

于 2011-09-20T12:36:07.483 回答
6

我遇到了这个问题并决定使用子命令。子命令可能是矫枉过正,但如果你发现你的程序在很多情况下都没有使用一些位置参数(就像我一样),那么子命令可能是一个很好的解决方案。

对于您给定的示例,我将使用以下内容:

parser = argparse.ArgumentParser(description="Foo bar baz")
subparsers = parser.add_subparsers(description='available subcommands')

parser_main = subparsers.add_parser('<main_command_name>')
parser_main.add_argument('arg1', help='arg1 is a positional argument that does this')
parser_main.add_argument('arg2', help='arg2 is a positional argument that does this')

parser_list = subparsers.add_parser('list', help='this is a subcommand that prints stuff')

options, args = parser.parse_args()

我遗漏了一些您可能想要包含的细节(如),这些细节在argparse 文档set_defaults(func=list)中有所提及。

于 2011-10-21T23:01:36.147 回答
2

我认为这nargs='*'很有帮助。

位置参数是可忽略的,那么您可以使用if来检查位置参数是真还是假。

http://docs.python.org/library/argparse.html#nargs

于 2012-05-20T05:12:38.163 回答
2

到目前为止,我能找到的最干净的方法是将解析分为两个阶段。首先检查-l/--list

parser = argparse.ArgumentParser(description="Foo bar baz")
parser.add_argument('-l', '--list', dest='list', action='store_true',
                    help='this is an optional argument that prints stuff')

options, remainder = parser.parse_known_args()

现在,由于您使用parse_known_args了 ,到此为止您不会出现错误,并且您可以决定如何处理remainder参数:

if options.list:
    print "I list stuff"
else:
    parser = argparse.ArgumentParser(add_help=False)
    parser.add_argument('arg1', help='arg1 is a positional argument that does this')
    parser.add_argument('arg2', help='arg2 is a positional argument that does this')
    options = parser.parse_args(remainder)

您可能希望在第一个解析器中设置使用选项,以使帮助字符串更好一些。

于 2018-12-17T03:48:39.153 回答
1

我可能在这里找到了解决方案。诚然,这是一个肮脏的黑客,但它的工作原理。

注意:以下所有内容均适用于 Python 3.3.2。

根据此处的答案,parse_args检查需要哪些操作,如果缺少任何操作,则会引发错误。我建议覆盖这种行为。

通过子类化ArgumentParser,我们可以定义一个新方法(此处ArgumentParser.error为原始方法),该方法将检查是否由于缺少某些参数而引发错误并采取必要的措施。代码如下:

import argparse
import sys
from gettext import gettext as _

class ArgumentParser(argparse.ArgumentParser):
    skip_list = []

    def error(self, message):
        # Let's see if we are missing arguments
        if message.startswith('the following arguments are required:'):
            missingArgs = message.split('required: ')[1].split(', ')
            newArgs = []    # Creating a list of whatever we should not skip but is missing
            for arg in missingArgs:
                if arg not in self.skip_list:
                    newArgs.append(arg)
                else:
                    self.skip_list.remove(arg)  # No need for it anymore
            if len(newArgs) == 0:
                return  # WARNING! UNTESTED! MAY LEAD TO SPACETIME MELTDOWN!
            else:   # Some required stuff is still missing, so we show a corrected error message
                message = _('the following arguments are required: %s') % ', '.join(newArgs)

        self.print_usage(sys.stderr)    # Original method behavior
        args = {'prog': self.prog, 'message': message}
        self.exit(2, _('%(prog)s: error: %(message)s\n') % args)

新方法首先检查错误是否是因为命令行中缺少参数(请参阅此处了解生成错误的代码)。如果是这样,该方法从错误消息中获取参数的名称并将它们放入一个列表 ( missingArgs) 中。

然后,我们遍历这个列表并检查哪些参数应该被跳过,哪些仍然是必需的。为了确定要跳过哪些参数,我们将它们与skip_list. 它是我们ArgumentParser子类中的一个字段,它应该包含要跳过的参数的名称,即使解析器需要它们。请注意,碰巧在其中的参数在skip_list找到时会从其中删除。

如果命令行中仍然缺少必需的参数,则该方法会引发更正的错误消息。但是,如果应跳过所有缺少的参数,则该方法将返回。

警告!的原始定义ArgumentParser.error表明,如果它在子类中被覆盖,则不应返回,而是退出或引发异常。因此,此处显示的内容可能不安全,可能会导致您的程序崩溃、您的计算机着火或更糟——它可能会蒸发掉您所有的茶。但是,在这种特殊情况下(缺少必需的参数),从方法返回似乎是安全的但它可能不是。你被警告了。

为了填充skip_list,我们可以使用如下代码:

class SpecialHelp(argparse._HelpAction):
    def __call__(self, parser, namespace, values, option_string=None):
        parser.print_help()
        print()
        for action in parser._actions:
            if action != self and action.required:
                parser.skip_list.append(argparse._get_action_name(action))

这个特定的类模仿了内置的help动作,但它没有退出,而是将所有剩余的必需参数插入到skip_list.

希望我的回答对您有所帮助,祝您好运。

于 2013-08-19T05:33:03.560 回答
0

它可能很难看,但这是我通常做的。

def print_list():
    the_list = ["name1", "name2"]
    return "{0}".format(the_list)

...
parser.add_argument("-l", "--list", action='version',
                    version=print_list(), help="print the list")
于 2014-01-10T14:12:53.810 回答