如何处理与argparse有关系的命令行参数?
假设我有一个名为myprog
的程序,它将一些文件名作为输入,并且我还希望使用命令行参数为每个文件设置打开模式。 例如如何处理与argparse有关系的命令行参数?
myprog --input a.txt --mode r --input b.txt --input c.txt --mode a
这意味着打开文件a.txt
与模式r
,文件b.txt
没有--mode阿根廷,所以用默认模式r
打开它,该文件c.txt
,使用a
模式打开它。
这是一个棘手的问题,因为argparse不会让您知道哪个--input
与某个--mode
相关联。您可以改变命令的结构,使文件名和模式是由标记字符分隔:
myprog --input a.txt:r --input b.txt --input c.txt:a
显然,这假设你没有文件后缀名为:<mode>
其中<mode>
是任何可接受文件模式。如果这是一个OK结构,那么就像编写自定义操作或类型来解析字符串并返回合适的对象一样简单。例如
def parse_fstr(s):
filename, _, mode = s.rpartition(':')
return (filename, mode or 'r')
其他解决方案可能涉及使用nargs='*'
然后解析出传递的参数列表。
最后,实现你所实际上要求不会有太大困难,我们需要做一个假设。假设将从左到右解析项目。鉴于图书馆的功能,这是唯一合理的选择实施,据我所知...
鉴于实施,我们可以做到这一点与自定义类型和自定义Action。该类型只是一个结构,可以将filename
和mode
分组在一起。每当我们点击一个--input
并将它追加到一个列表中(这是支持开箱的),我们将使用构造这种类型的新实例。接下来,我们将编写一个自定义操作,以在每次插入--mode
参数时更新列表中最后一个“文件结构”的mode
。
import argparse
class FileInfo(object):
def __init__(self, name, mode='r'):
self.name = name
self.mode = mode
def __repr__(self):
return 'FileInfo(name={!r}, mode={!r})'.format(self.name, self.mode)
class UpdateMode(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
try:
last_file_info = namespace.input[-1]
except IndexError:
# No file-info added yet. Error.
parser.error('{} must come after an --input'.format(option_string or '--mode'))
last_file_info.mode = values
parser = argparse.ArgumentParser()
parser.add_argument('--input', action='append', type=FileInfo)
parser.add_argument('--mode', action=UpdateMode)
print(parser.parse_args())
我选择抛出一个错误,如果--mode
任何--input
之前显示出来,但如果2 --mode
遵循--input
,我只是覆盖以前的值。如果您想要进行更多错误检查,那么在FileInfo
类中编写更多代码以确保在您更新模式时尚未设置任何模式。
是的,''parse_args'遍历'argv'('sys.argv [1:]'),或者处理定位和选择权。各自的'nargs'控制给每个'Action'分配多少个字符串。所以你的自定义Action类应该像广告一样工作。 – hpaulj
如果在命令行是这样的:
myprog --input a.txt --mode r --input c.txt --mode a --input b.txt
这是确定添加一些像这样的代码:
import argparse
parser = argparser.ArgumentParser()
parser.add_argument('--input', action='append')
parser.add_argument('--mode', action='append')
args = parser.parse_args()
args_dict = vars(args)
然后你就可以分析参数对象,args_dict变量。值是这样的:
$ python test.py --input test.txt --mode w --input test3.txt --input test2.txt --mode a
{'mode': ['w', 'a'], 'input': ['test.txt', 'test3.txt', 'test2.txt']}
可以遍历都“输入”键和“模式”在args_dict变量键,为保持输入列表中(它的“的test2.txt”这里),你可以用'r'模式打开它。
但是,如果您的命令行必须写类似:
myprog --input a.txt --mode r --input b.txt --input c.txt --mode a
我不认为这是容易解析带“R”模式下的b.txt,因为argparse不知道哪个模式结合相对输入...
获得从@mgilson灵感的意见和答案,我已经找到了另一种方式来定义Action子类,使‘模式’输入有用。
class ExtendReadOnlyAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
inputs = namespace.input
modes = getattr(namespace, self.dest)
if modes is None:
modes = []
modes.extend(['r' for i in range(len(inputs) - len(modes))])
modes[-1] = values
setattr(namespace, self.dest, modes)
而且客户端代码可以是这样的:
import argparse
parser = argparser.ArgumentParser()
parser.add_argument('--input', action='append')
parser.add_argument('--mode', action=ExtendReadOnlyAction)
args = parser.parse_args()
args_dict = vars(args)
然后我们可以分析参数对象,args_dict变量更容易。如果在命令行是这样的:
$ python test.py --input test.txt --mode w --input test2.txt --input test3.txt --mode a
结果将是:
{'mode': ['w', 'r', 'a'], 'input': ['test.txt', 'test2.txt', 'test3.txt']}
在其他特殊的方式,如果命令行是这样的:
$ python test.py --input test.txt --mode w --input test2.txt --input test3.txt --input test4.txt
结果将是:
{'input': ['test.txt', 'test2.txt', 'test3.txt', 'test4.txt'], 'mode': ['w']}
而且n您可以更轻松地解析dict,输入参数中的'test2.txt〜test4.txt'将具有默认'r'模式:)
如果您使用的是pycharm,则可以使用设置指定命令行参数。 –
那么,问题是什么? –
你保证每个'--input'都有对应的'--mode'吗?如果是这样,那么你可以在'input'和'mode'上使用'append''动作,然后''压缩'列表。如果没有(根据你的例子看起来就像是这种情况),那么事情就会变得更加困难,除非你愿意重组命令行 - 例如'myprog --input a.text r --input b.txt --input c.txt a ...' – mgilson