使用Python的argparse模块重构命令行是否可行?

6
我有一个Python脚本,读取一个包含某个其他工具命令行调用的文件。我想在调用该工具之前修改此调用的选项。例如,我可能会执行以下转换:
my_util --input file1.txt --option1 red --option2 blue

...变成了这样:

my_util --input file1_001.txt --option1 red --option3 green

更准确地说,我将在参数作为列表上工作。
我认为使用 argparse 模块是最简单的方法:我可以解析参数,根据需要更改、添加或删除选项,然后重构命令行。
但是,如何进行最后一步呢?给定由 parse_args() 返回的 Namespace 对象,我能否轻松重构命令行选项列表,例如可以传递给 subprocess.Popen() 的列表?
2个回答

3

命名空间对象只是一个简单的对象子类,因此您可以使用vars将其值作为字典取出:

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo')
>>> args = parser.parse_args(['--foo', 'BAR'])
>>> vars(args)
{'foo': 'BAR'}

或者你可以直接分配给一个类,并将参数作为类变量提取出来:

>>> class C(object):
...     pass
...
>>> c = C()
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo')
>>> parser.parse_args(args=['--foo', 'BAR'], namespace=c)
>>> c.foo
'BAR'

使用这些结构之一来测试/替换参数并将结果传递给Popen将非常容易。

1
是的,那就是我最终所做的。唯一的注意事项是,这个对象不会区分必需的位置参数和选项。 - detly

0

我知道这是一个老问题,但我刚遇到了同样的问题。 我意识到我需要的只是一种迭代Action对象的方法。不幸的是,ArgParser本身不公开内部列表。但是,这些对象是由add_argument()返回的,因此我可以构造自己的列表。好吧,在每个调用周围放置actions.append()看起来对我来说太麻烦了,所以我将所有选项存储在元组中:

def add_argument(*args, **kwargs):
    return (args, kwargs)

parser = argparse.ArgumentParser()
options = (
    add_argument('--verbose', action='store_true'),
    add_argument('--author'),
    add_argument('--subject', required=True),
    add_argument('--cache', nargs='?'),
    add_argument('files', nargs=''),
)
actions = []
for (args, kwargs) in options:
    actions.append(parser.add_argument(*args, **kwargs))
args = parser.parse_args()

在这个点上,选项被解析为args,并且所有的argparse.Action对象都被存储在actions列表中。然后我可以遍历这个列表并像这样重建选项:

cmdline = []
for action in actions:
    value = getattr(args, action.dest)
    if action.required or value != action.default:
        if action.option_strings:
            cmdline.append(action.option_strings[0])
        if action.nargs is None:
            cmdline.append(value)
        elif action.nargs == '?':
            if value != action.const:
                cmdline.append(value)
        elif action.nargs != 0:
            cmdline += value

在我的特定情况下,我还想从命令行中删除一些选项。为了做到这一点,我只需通过调用parser.add_argument()单独添加它们,而不是通过options元组添加。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接