【问题标题】:How can I easily create a python argparse argument with an inverse?如何轻松创建带有逆的 python argparse 参数?
【发布时间】:2015-08-03 17:21:57
【问题描述】:

在 Python 3 中使用 argparse,我想创建一对互补的参数:

--log-file=~/some-default-log-filename.txt
--no-log-file

正如示例所暗示的,默认情况下,日志文件参数将具有默认值(文件名)。您可以通过为--log-file 指定不同的字符串值来更改它,或者通过指定--no-log-file 来完全删除日志文件。

在 argparse 中执行此操作的优雅方法是什么?我根本找不到任何方法来做反向/互补参数,不介意字符串参数在哪里。

如果我执行args = parser.parse_args() 时,最好的情况是args.log_file 包含日志文件名(包括默认名称)或None(如果已指定no-log-file 选项)。

【问题讨论】:

  • 你看过ArgumentParser.add_mutually_exclusive_group()
  • Rob,我有(实际上我在其他地方使用过),但这涉及到创建两个选项。 --no 前缀是一个常见的概念,我希望/假设有一个 argparse 机制可以直接支持它。
  • 为什么不这样做,如果没有日志文件,用户只是不提供--log-file
  • jonrsharpe,不幸的是,默认情况下没有日志文件的要求。

标签: python-3.x command-line-arguments argparse


【解决方案1】:

检查此结尾以获取基于 store_const 的解决方案。

我记得看到一个旧的 python 错误问题,它建议用一些可以自动处理 --foo--no-foo 的代码扩展 argparse,也许还有其他一些变体。也许我以后会找到。

但目前argparse 没有符合您要求的机制。

nargs='?'constdefault 旨在处理像您这样的 3 折盒。

# no --foo, assign the 'default'
--foo # without arg, assign the 'const'
--foo arg  # assign the supplied string

虽然语法并不完全符合您的要求,但我认为它为您的用户提供了相同的控制权。

为了更接近您想要的语法,您必须同时创建 logfile 参数和 no-log 参数,然后使用简单的 pos-parsing 测试将两者“合并”。

parser.add_argument('--log-file', ....)
parser.add_argument('--no-log', action='store_true')

及以后:

if args.no_log:
    args.log_file = None

如果您必须创建许多这样的参数对,您可以定义一个辅助函数:

def make_inverse_arg(parser, *args, **kwargs):
    parser.add_argument(*args, **kwargs)
    # define inverse
    arg1 = '--no-'+args[1][2:]
    parser.add_argument(arg1, action='store_true')
    # could be more robust, but you get the idea
    def post_test():
         ...
    return post_test

如果--no-foo 被定义为'store_const' 参数,const=None--foo 相同的dest,那么它只会在None 存在时将它放在命名空间中。 default=SUPPRESS 确保它不会将自己的默认值放入命名空间。

parser=argparse.ArgumentParser()
parser.add_argument('--no-foo', dest='foo', action='store_const', const=None,
     default=argparse.SUPPRESS)
parser.add_argument('--foo',default='test')

In [329]: parser.parse_args([])
Out[329]: Namespace(foo='test')

In [330]: parser.parse_args('--foo xxx'.split())
Out[330]: Namespace(foo='xxx')

In [331]: parser.parse_args('--foo xxx --no-foo'.split())
Out[331]: Namespace(foo=None)

In [332]: parser.parse_args('--no-foo --foo xxx'.split())
Out[332]: Namespace(foo='xxx')

In [333]: parser.parse_args('--no-foo'.split())
Out[333]: Namespace(foo=None)

如果有冲突,--foo--no-foo 中的最后一个确定命名空间中的内容。

【讨论】:

  • 这似乎效果最好,并直接解决了我的情况。我喜欢你的通用 make_inverse_arg 函数。
【解决方案2】:

这不是完全您正在寻找的东西,但我会这样做:

parser.add_argument(
    "--log-file", 
    const="~/some-default-log-filename.txt", 
    default=None,
    dest="log_file",
    nargs="?"
)

这处理三种情况:

  • ... --log-file mylog.txt ... - 登录到用户指定的文件;
  • ... --log-file ... - 登录到const 默认文件;和
  • ... - 使用 defaultNone

请参阅the docs on nargs 了解更多信息。

【讨论】:

  • 是的,这是一个好的开始,谢谢。但不,不幸的是,这不是我要找的。最重要的一点是,默认的 is 会登录到某个地方。用户还需要能够切换该日志文件的目标,并将其完全关闭。
  • @AndrewFerrier 我明白了。那么,我认为您的问题的直接答案是“否”。你可以例如将type 定义为自定义函数,并允许用户输入--log-file=off 以停用日志记录。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-29
  • 2020-11-25
  • 2012-06-22
  • 1970-01-01
  • 2015-03-10
  • 2023-03-07
  • 2012-01-18
相关资源
最近更新 更多