argparse:无序处理某些参数

2024-06-17 14:47:34 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个python应用程序,它有几个可重复的参数,交错顺序对这些参数很重要。e、 g.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累积到一个异构的“要做的事情”列表中,然后在事后处理它们。但是,如果有一个合理的直截了当的方法来解决这个问题,而不增加一层间接性,我宁愿不跳过这个额外的环


Tags: addappparser参数foologgingdefargparse
2条回答

看到选项时不要调用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)

按照古老的传统,我在发帖后很快就找到了答案

如果其他人在这里登陆,我会创建第二个解析器,并使用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()

相关问题 更多 >