基于另一个选项的 argparse 默认选项

41

假设我有一个argparse的Python脚本:

import argparse

parser = argparse.ArgumentParser()
    
parser.add_argument("--foo", required=True)

现在我想添加另一个选项 --bar,默认情况下将"_BAR"附加到由 --foo 参数指定的任何内容。

我的目标:

>>> parser.parse_args(['--foo', 'FOO'])
>>> Namespace(foo='FOO', bar="FOO_BAR")

并且

>>> parser.parse_args(['--foo', 'FOO', '--bar', 'BAR'])
>>> Namespace(foo='FOO', bar="BAR")

我需要类似这样的东西:

parser.add_argument("--bar", default=get_optional_foo + "_BAR")

嗯,argparse如何本地化实现这个?也许可以传递一个参数名称元组和函数到要传递的函数中。 - SIGSTACKFAULT
2个回答

31

作为第一次尝试,我会使用一个 after-argparse 函数使其工作起来。

def addbar(args):
    if args.bar is None:
        args.bar = args.foo+'_BAR'
如果这个操作需要反映在帮助文档中,请自己添加。
理论上,您可以编写一个定制的 Action 来为 foo 设置 bar 值,但这需要更熟悉 Action 类。
我尝试了一个自定义的 Action 来调整 bar 操作的默认值,但这很棘手。在任何参数被处理之前,parse_args 就会在一开始使用默认值。

我想知道为什么这个被踩了。没有其他人提出解决方案,更别说更好的了。 - hpaulj
不知道,但我给你点赞。我喜欢这个解决方案的简洁性,比起自定义操作来说更好,尽管一个添加参数依赖关系的ArgumentParser子类会很酷。 - sfink

15

这是另一个尝试编写自定义Action类的例子

import argparse
class FooAction(argparse.Action):
    # adapted from documentation
    def __call__(self, parser, namespace, values, option_string=None):
        setattr(namespace, self.dest, values)
        defaultbar = getattr(namespace, 'bar')
        try:
            defaultbar = defaultbar%values
        except TypeError:
            # BAR has already been replaced
            pass
        setattr(namespace, 'bar', defaultbar)

parser = argparse.ArgumentParser()
parser.add_argument("--foo", required=True, action=FooAction)
parser.add_argument("--bar", default="%s_BAR")

args = parser.parse_args(['--foo', 'Foo', '--bar', 'Bar'])
# Namespace(bar='Bar', foo='Foo')
args = parser.parse_args(['--foo', 'Foo'])
# Namespace(bar='Foo_BAR', foo='Foo')
args = parser.parse_args(['--bar', 'Bar', '--foo', 'Foo'])
# Namespace(bar='Bar', foo='Foo')

请注意,该类必须知道--bar参数的dest。同时,我使用'%s_BAR'来区分默认值和非默认值。这处理了--bar出现在--foo之前的情况。

使这种方法复杂的因素包括:

  • 默认值在add_argument时间评估。
  • 默认值在parse_args开始时放置在名称空间中。
  • 标记(可选)参数可以以任何顺序出现
  • Action类没有设计用于处理交互参数。
  • 在默认情况下,bar操作将不会被调用。
  • bar默认值可以是函数,但是必须在parse_args之后检查是否需要评估它。

虽然这个自定义操作做到了这一点,但我仍然认为我其他答案中的addbar函数是一个更清晰的解决方案。


我尝试过这个,但是__call__从未被调用。 - A T
1
@AT,如果用户提供了一个值,则会调用“Action”,如果是“required”,则始终如此。当仅返回默认值时,不会调用它。 - hpaulj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接