可以用Python的argparse重构命令行吗?
我有一个Python脚本,它可以读取一个文件,这个文件里包含了某个工具的命令行调用。我想在调用这个工具之前,修改一下这些调用的选项。比如,我可能会把:
my_util --input file1.txt --option1 red --option2 blue
...改成这样:
my_util --input file1_001.txt --option1 red --option3 green
(更准确地说,我会把参数当成列表来处理。)
我觉得使用argparse
模块是最简单的方法:我可以解析这些参数,根据需要修改、添加或删除选项,然后重新构建命令行。
但是,最后一步我该怎么做呢?给定Namespace
对象,它是通过parse_args()
返回的,我能否轻松地重新构建一个命令行选项的列表,这样就可以传递给subprocess.Popen()
?
2 个回答
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
元组。
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
是相对简单的。