如何确定是否在命令行上实际指定了 argparse 参数?

How to find out if argparse argument has been actually specified on command line?

我正在使用 arparse 使用在命令行上指定的值来更新配置字典。因为我只想更新命令行中明确提到的值的配置中的值。

因此,我尝试通过检查每个操作是否 getattr(args, action.dest) == action.default 或转换后的参数类型是否相等来识别未指定的参数。然后我更新字典中的所有值,这是错误的。

但这当然会失败,如果我在命令行上明确指定一个与我的默认参数相同的参数。是否有可能使用 argparser 识别这些明确提到的参数,或者我有 在 sys.argv?

中手动识别它们

谢谢!

编辑:

为了让我的意图更清楚。我有如下论点:

parser.add_argument('--test', default='meaningful_default')

和类似

的配置

config = { 'test' : 'nondefault_val'}

现在我只想用明确指定的参数更新配置。将 args 属性与默认值进行比较,只要我不指定类似 prog.py --test meaningful_default 的值来再次更新我的配置,而该值恰好也是默认值

parser 在解析时维护一个 seen_actions set 对象(在 _parse_known_args 方法中)。在解析结束时,它会根据所需的参数(带有 required=True 的参数)检查此集合,并可能会发出错误。一种变体也用于互斥组。

但是这个变量在那个函数之外是不可用的。缺少某种 'hook' 允许您在 parse_args 操作中应用自己的测试,最好的选择是测试默认值。或者你可以看看sys.argv[1:].

默认 defaultNone。这对于此目的来说很好,因为您的用户无法提供此值。也就是说,没有字符串可以转换为 None(至少在任何正常的 type 方法中都没有)。

parser.add_argument('--foo') # default=None
...
if args.foo is None:
    # clearly foo has not been specified.
    args.foo = 'the real default'
else:
    # foo was specified
    pass

如果您更喜欢使用 argparse 并能够指定默认值,则有一个使用两个解析器的简单解决方案。

我。定义您的主要解析器并使用适当的默认值解析您的所有参数:

parser = argparse.ArgumentParser()
parser.add_argument('--test1', default='meaningful_default1')
parser.add_argument('--test2', default='meaningful_default2')
...
args, unparsed = parser.parse_known_args()

二.使用 argument_default=argparse.SUPPRESS 定义辅助解析器以排除未指定的参数。添加来自主解析器的所有参数但没有任何默认值:

aux_parser = argparse.ArgumentParser(argument_default=argparse.SUPPRESS)
for arg in vars(args): aux_parser.add_argument('--'+arg)
cli_args, _ = aux_parser.parse_known_args()

这不是一个非常优雅的解决方案,但与 argparse 及其所有优点配合使用效果很好。

您可以使用自定义操作来判断 arg 值是默认值还是在命令行上设置:

import argparse

class FooAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        setattr(namespace, self.dest, values)
        setattr(namespace, self.dest+'_nondefault', True)

parser = argparse.ArgumentParser()
parser.add_argument('--test0', default='meaningful_default', action=FooAction)
parser.add_argument('--test1', default='meaningful_default', action=FooAction)

args = parser.parse_args('--test0 2'.split())

if hasattr(args, 'test0_nondefault'):
    print('argument test0 set on command line')
else:
    print('default value of test0 is used')

if hasattr(args, 'test1_nondefault'):
    print('argument test1 set on command line')
else:
    print('default value of test1 is used')

您可以使用“const" and "default" to emulate what you want. "nargs”的组合,在这种情况下必须是 '?'。例如:

args_group.add_argument('--abc',
                         metavar='',
                         nargs='?',
                         action='store',
                         const='github.com',
                         default='',
                         help='blabla [ default: %(const)s ]')

然后abc的值将根据不同的命令行参数如下。

abc 不在命令行中:

abc =

--abc:

abc = github.com

--abc whosebug.com:

abc = whosebug.com

所以你会知道 abc 为空时不会出现在命令行中,例如:

if not args.abc:
    # to something