Python Argparse:获取用于命名空间变量的命令行参数

Posted

技术标签:

【中文标题】Python Argparse:获取用于命名空间变量的命令行参数【英文标题】:Python Argparse: Get the command-line argument used for a Namespace variable 【发布时间】:2021-12-23 08:00:22 【问题描述】:

是否有适当的或至少更好的方法来获取用于设置命名空间参数(属性)值的命令行参数?

我目前正在使用这样的东西:

>>> import argparse
>>>
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--do-a', '-a',
...     default=False, action='store_true',
...     dest='process_foo',
...     help="Do some awesome a to the thing.")
>>> args = parser.parse_args()
>>>
>>> def get_argument(parser, dest):
...     for action in parser._actions:
...         if action.dest == dest:
...             return action.option_strings[0], action.help
...     return dest, ''
...
>>> get_argument(parser, 'process_foo')
('--do-a', 'Do some awesome a to the thing.')

这可能适用于 99% 的情况;但是,如果多个命令行参数可以设置process_foo,这将不起作用,并且访问“隐藏”实例属性(parser._actions)充其量是笨拙的。有没有更好的方法来做到这一点?

我将此添加到一个模块中,所有数据科学流程都会继承哪些日志环境和其他内容,以便我们具有更好的可重复性。有问题的模块已经自动记录设置、参数、命令行参数等,但在某些方面不是很友好。

【问题讨论】:

为什么不直接使用args.process_foo?这不适用于您的应用程序吗? 【参考方案1】:

我建议创建您自己的从argarse.Action 派生的操作类,它不仅将解析值存储在命名空间中,还将解析值的选项字符串存储在命名空间中。

完整的工作示例:

import argparse

class StoreTrueWithOptionStringAction(argparse.Action):
    def __init__(self,
                 option_strings,
                 dest,
                 default=None,
                 required=False,
                 help=None,
                 metavar=None):
        super().__init__(option_strings=option_strings,
                         dest=dest,
                         nargs=0,
                         const=True,
                         default=default,
                         required=required,
                         help=help)
    
    def __call__(self, parser, namespace, values, option_string=None):
        setattr(namespace, self.dest, self.const)
        if option_string is not None:
            setattr(namespace, f'self.dest_option_string', option_string)

def get_parser():
    parser = argparse.ArgumentParser()
    parser.add_argument('--bar', action=StoreTrueWithOptionStringAction, dest='foo', default=False)
    parser.add_argument('--baz', action=StoreTrueWithOptionStringAction, dest='foo', default=False)
    return parser

def main():
    parser = get_parser()
    args = parser.parse_args()
    print(args.foo)
    print(args.foo_option_string)

if __name__ == '__main__':
    main()

输出:

$ python3 main.py --bar
True
--bar
$ python3 main.py --baz
True
--baz

【讨论】:

【参考方案2】:

不用担心_actions 的“隐藏性”。这是存储对由add_argument 创建的所有Actions 的引用的主要列表。您不应该摆弄列表,但您当然可以使用它来收集信息。

add_argument 创建一个Action 对象,将其放入_actions(通过_add_action 方法),并返回它。如果您不喜欢使用_actions,您可以使用add_argument 返回的对象收集您自己的引用列表。

我从_add_action 看到,它还将标记的操作放入self._option_string_actions 字典中,从而更容易将选项字符串与其action 配对。

解析不会对parser、其属性或actions 进行任何更改。虽然它有各种局部变量(在_parse_known_args 方法中),但唯一改变的是args 命名空间。

它使对args 的访问尽可能通用,包括getattrsetattrhasattr。这包括在解析开始时设置默认值。解析器不会记录哪个选项字符串触发了特定的take_action 和随后的setattr。然而Action__call__ 确实得到了字符串。对于最常见的“store_action”,调用是

def __call__(self, parser, namespace, values, option_string=None):
    setattr(namespace, self.dest, values)

我认为所有定义的Action 子类都使用self.dest,但用户定义的子类不必这样做。他们甚至可以设置其他命名空间属性,或者不设置(例如 help 没有设置任何东西)。他们还可以记录option_string

也可以设置命名空间属性而不通过定义的操作。你的dest 测试对这些没有帮助。

https://docs.python.org/3/library/argparse.html#parser-defaults

展示了如何在不在参数中定义属性的情况下设置属性。子命令显示了如何使用它来定义将与特定解析器一起使用的函数。

https://docs.python.org/3/library/argparse.html#the-namespace-object 还表明可以提供部分初始化的命名空间。

【讨论】:

以上是关于Python Argparse:获取用于命名空间变量的命令行参数的主要内容,如果未能解决你的问题,请参考以下文章

类定义中的 Python argparse 命名空间

使用其他命名空间/字典更新 argparse 命名空间

带有嵌套命名空间的 argparse 子命令

在 Python 中轻松地将变量从/向命名空间/字典转储

复用代码Python接收命令行参数:argparse模块

python argparse命名位置参数?