【问题标题】:argparse: Handle certain arguments out of orderargparse:无序处理某些参数
【发布时间】:2021-09-05 06:56:23
【问题描述】:

我有一个 python 应用程序,它有一些可重复的参数,交错顺序很重要。例如app -f 1 -b 2 -f 3app -f 1 -f 3 -b 2 不是同一个命令。

问题是我也有详细控制参数,我希望它影响在操作中执行的代码的日志记录行为。

有没有办法让argparse 乱序处理某些参数,以便在处理其他参数之前应用详细程度控制,而不管它在argv 中的什么位置?

# test.py
import argparse
import logging

def foo(x):
  logging.info(f'hi foo {x}')

def bar(x):
  logging.debug(f'hi bar {x}')

def SetVerbosity(log_level):
    class Action(argparse.Action):
        def __call__(self, parser, namespace, values, option_string=None):
            logging.getLogger(values).setLevel(level=log_level)

    return Action

class PerformFoo(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        foo(values)

class PerformBar(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        bar(values)

parser = argparse.ArgumentParser()

parser.add_argument('-v', '--verbose', nargs='?', action=SetVerbosity(logging.INFO))
parser.add_argument('-vv',             nargs='?', action=SetVerbosity(logging.DEBUG))

parser.add_argument('-f', '--foo', metavar='VAL', action=PerformFoo, help='Do a foo')
parser.add_argument('-b', '--bar', metavar='VAL', action=PerformBar, help='Do a bar')

logging.basicConfig()
parser.parse_args()
# No problem
python test.py -v -f 1 -b 2 -f 3
INFO:root:hi foo 1
INFO:root:hi foo 3

# kind of unfortunate
app -f 1 -b 2 -f 3 -v
*crickets*

作为后备,我知道我可以将-f-b 累积到一个异构的“待办事项”列表中,然后在事后处理它们。但是,如果有一种相当简单的方法来解决这个问题,而无需增加间接层,我宁愿不跳过这个额外的环节。

【问题讨论】:

    标签: python argparse


    【解决方案1】:

    当看到选项时不要打电话给foovar。相反,请在解析完所有选项后收集要执行的操作列表。

    类似

    import argparse
    import logging
    
    def foo(x):
      pass
    
    def bar(x):
      pass
    
    def SetVerbosity(value):
        class Action(argparse.Action):
            def __call__(self, parser, namespace, values, option_string=None):
                logging.getLogger(values).setLevel(level=value)
    
        return Action
    
    class PerformFoo(argparse.Action):
        def __call__(self, parser, namespace, values, option_string=None):
            namespace.to_do += [(foo, values)]
    
    class PerformBar(argparse.Action):
        def __call__(self, parser, namespace, values, option_string=None):
            namespace.to_do += [(bar, values)]
    
    parser = argparse.ArgumentParser()
    
    parser.add_argument('-v', '--verbose', nargs='?', action=SetVerbosity(logging.INFO))
    parser.add_argument('-vv',             nargs='?', action=SetVerbosity(logging.DEBUG))
    
    parser.add_argument('-f', '--foo', metavar='VAL', action=PerformFoo, help='Do a foo')
    parser.add_argument('-b', '--bar', metavar='VAL', action=PerformBar, help='Do a bar')
    
    args = parser.parse_args()
    
    for f, v in args.to_do:
        f(v)
    

    【讨论】:

    • 感谢您的回答,但我确实在问题中声明我明确想知道是否有替代方案,这是我目前的后备方案。
    • 不,没有。参数只是按照它们出现的顺序处理。
    • argparse 不太适合处理顺序很重要的参数。底层解析方法尝试处理给定的参数,而不保留顺序信息。特殊行动可以改变这一点。 append 例如允许重复的选项。你的特殊行为也能做到,但从某种意义上说,它们违反了argparse 的核心理念——先解析然后行动。
    • @hpaulj 可以说,versionhelp 也违反了这个想法(尽管它们都退出了脚本,这使得它们有点不同的特殊情况)。
    【解决方案2】:

    按照历史悠久的传统,我在发布问题后不久就设法找到了答案。

    万一其他人登陆这里,我设法通过创建第二个解析器并使用parse_known_args() 调用它来做到这一点,以便忽略非详细参数。

    verbosityParser = argparse.ArgumentParser(add_help=False)
    parser = argparse.ArgumentParser()
    
    verbosityParser.add_argument('-v', '--verbose', nargs='?', action=SetVerbosity(logging.INFO))
    verbosityParser.add_argument('-vv',             nargs='?', action=SetVerbosity(logging.DEBUG))
    
    # Still add verbosity to the "main" parser so that it shows up in help
    parser.add_argument('-v', '--verbose', nargs='?')
    parser.add_argument('-vv',             nargs='?')
    parser.add_argument('-f', '--foo', metavar='VAL', action=PerformFoo, help='Do a foo')
    parser.add_argument('-b', '--bar', metavar='VAL', action=PerformBar, help='Do a bar')
    
    logging.basicConfig()
    verbosityParser.parse_known_args()
    parser.parse_args()
    

    【讨论】:

      猜你喜欢
      • 2017-10-14
      • 2017-11-26
      • 2017-01-14
      • 1970-01-01
      • 2012-03-08
      • 1970-01-01
      • 1970-01-01
      • 2022-06-11
      • 2020-03-04
      相关资源
      最近更新 更多