首页 > 解决方案 > 来自子解析器的顶级解析器上的 Python argparse set_defaults

问题描述

我有一个argparse带有多个子解析器的程序。如果未指定顶级参数的值,我希望它取决于子解析器的选择。这可以通过set_defaults()在每个子解析器上使用来部分完成。但是,传递的值不像真正的默认值那样起作用,因为即使显式提供了顶级参数,它也具有优先权。

我是否在argparse模块中遗漏了一些允许特定于子解析器的默认值屈服于顶级解析器的东西?下面是一个演示我想要的用例的玩具示例

import argparse

# Top-level parser
parser = argparse.ArgumentParser()
parser.add_argument('-t', '--time', type=str)

# Add subparsers with options
actions = parser.add_subparsers(dest='action', metavar='action')
actions.required = True
eat = actions.add_parser('eat')
eat.add_argument('-f', '--food', type=str, default='pizza')
order = actions.add_parser('order')
order.add_argument('-i', '--item', type=int, required=True)

# Attempt to set main parser's --time depending on subparser selection
eat.set_defaults(time='now')
order.set_defaults(time='later')

# Tests that work as expected
print(parser.parse_args(['order', '--item', 0]))  # Namespace(action='order', item=0, time='later')
print(parser.parse_args(['eat']))                 # Namespace(action='eat', food='pizza', time='now')

# Tests that DO NOT work
# Actual result:  the --time flag of `parser` is ignored in preference of each subparser's default
# Desired result: explicit usage of --time should override the subparser defaults like the comments below
# Namespace(action='order', item=0, time='before')
# Namespace(action='eat', food='pizza', time='after')
print(parser.parse_args(['--time', 'before', 'order', '--item', 0]))
print(parser.parse_args(['--time', 'after', 'eat']))

标签: pythonargparse

解决方案


似乎子解析器参数覆盖了
从顶级解析器创建的命名空间条目,因为它们具有
相同的名称。所以命名空间最终只有一个“时间”
条目(而不是一个用于顶级解析器,一个用于
子解析器);它的值是写入它的最后一个值:
子解析器的值。

或者,在使用特定的子解析器之前,也许只在主解析器中使用 arg,
并更改它的默认值(在主解析器中) ?

import argparse

parserMain = argparse.ArgumentParser()
parserMain.add_argument('--arg', type=str)
subparsers = parserMain.add_subparsers()

parserX = subparsers.add_parser('x')
# This would overwrite the value of 'arg' in the Namespace:
#parserX.set_defaults(arg='defaultValForX')
# So, set default in main parser, before using sub-parser:
parserMain.set_defaults(arg='defaultValForX')
print(parserMain.parse_args(['x']))
print(parserMain.parse_args(['--arg', 'explicitVal', 'x']))

parserY = subparsers.add_parser('y')
# This would overwrite the value of 'arg' in the Namespace:
#parserY.set_defaults(arg='defaultValForY')
# So, set default in main parser, before using sub-parser:
parserMain.set_defaults(arg='defaultValForY')
print(parserMain.parse_args(['y']))
print(parserMain.parse_args(['--arg', 'explicitVal', 'y']))

推荐阅读