如何让argparse从带有选项而不是前缀的文件中读取参数

Bry*_*ley 14 python python-2.7 argparse

我想知道如何使用python的argparse模块从命令行和文本文件中读取参数.我知道argparse的,fromfile_prefix_chars但这不是我想要的.我想要这个行为,但我不想要语法.我想要一个如下所示的界面:

$ python myprogram.py --foo 1 -A somefile.txt --bar 2
Run Code Online (Sandbox Code Playgroud)

当argparse看到-A时,它应该停止从sys.argv或我给它的任何东西读取,并调用我写的函数,它将读取somefile.text并返回一个参数列表.当文件用尽时,它应该继续解析sys.argv或其他什么.重要的是文件中的参数处理顺序发生(即:应该处理-foo,然后处理文件中的参数,然后是-bar,以便文件中的参数可以覆盖--foo,和 - bar可能会覆盖文件中的内容).

这样的事情可能吗?我可以编写一个自定义函数,将新参数推送到argparse的堆栈上,或者是那种效果吗?

pok*_*oke 24

您可以使用argparse.Action打开文件的自定义解析此文件,解析文件内容,然后添加参数.

例如,这将是一个非常简单的操作:

class LoadFromFile (argparse.Action):
    def __call__ (self, parser, namespace, values, option_string = None):
        with values as f:
            parser.parse_args(f.read().split(), namespace)
Run Code Online (Sandbox Code Playgroud)

你可以这样使用:

parser = argparse.ArgumentParser()
# other arguments
parser.add_argument('--file', type=open, action=LoadFromFile)
args = parser.parse_args()
Run Code Online (Sandbox Code Playgroud)

然后,生成的命名空间args还将包含也从文件加载的任何配置.

如果需要更复杂的解析,还可以先分别解析文件内配置,然后有选择地选择应该接管哪些值.例如,禁止在配置文件中指定另一个文件可能是有意义的:

def __call__ (self, parser, namespace, values, option_string=None):
    with values as f:
        contents = f.read()

    data = parser.parse_args(contents.split(), namespace=namespace)
    for k, v in vars(data).items():
        if v and k != option_string.lstrip('-'):
            setattr(namespace, k, v)
Run Code Online (Sandbox Code Playgroud)

当然,您也可以使文件读取更复杂,例如首先从JSON读取.

  • 啊哈!关键是要意识到解析器被传递给自定义操作,并且您可以使用该解析器来处理文件的内容。谢谢。 (3认同)
  • 唉,如果您的任何参数设置为Required,则会失败. (3认同)

hpa*_*ulj 6

你评论说

\n\n
\n

我需要能够编写自己的函数来读取该文件并返回参数(它不是每行一个参数的格式)\xe2\x80\x93

\n
\n\n

现有的前缀文件处理程序中有一项规定可以更改文件的读取方式。该文件由“私有”方法读取,parser._read_args_from_files但它调用一个简单的公共方法,将一行转换为字符串,默认每行一个参数操作:

\n\n
def convert_arg_line_to_args(self, arg_line):\n    return [arg_line]\n
Run Code Online (Sandbox Code Playgroud)\n\n

它是这样编写的,因此您可以轻松地自定义它。\n https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.convert_arg_line_to_args

\n\n
\n

此方法的一个有用的重写是将每个空格分隔的单词视为参数:

\n
\n\n
def convert_arg_line_to_args(self, arg_line):\n    for arg in arg_line.split():\n        if not arg.strip():\n            continue\n        yield arg\n
Run Code Online (Sandbox Code Playgroud)\n\n

test_argparse.py单元测试文件中,有一个针对此替代方案的测试用例。

\n\n
\n\n

但是,如果您仍然想使用参数选项而不是前缀字符来触发此读取,那么自定义操作方法是一个不错的选择。

\n\n

不过,您可以编写自己的函数,argv在传递给parser. 可以仿照它parser._read_args_from_files

\n\n

所以你可以写一个像这样的函数:

\n\n
def read_my_file(argv):\n    # if there is a \'-A\' string in argv, replace it, and the following filename\n    # with the contents of the file (as strings)\n    # you can adapt code from _read_args_from_files\n    new_argv = []\n    for a in argv:\n        ....\n        # details left to user\n    return new_argv\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后使用以下命令调用解析器:

\n\n
parser.parse_args(read_my_file(sys.argv[1:]))\n
Run Code Online (Sandbox Code Playgroud)\n\n

是的,这可以包装在ArgumentParser子类中。

\n