如何传递文件中包含的命令行参数并保留该文件的名称?

Ton*_*has 5 python parameter-passing command-line-arguments argparse

我有一个使用命令行参数的脚本,我想实现两个参数传递方案,即:

  • 在命令行输入参数。
  • 将参数列表存储在文件中,然后通过命令行将此文件的名称传递给程序。

为此,我将参数传递fromfile_prefix_charsArgumentParser构造函数。

script.py

from argparse import ArgumentParser
parser = ArgumentParser(fromfile_prefix_chars='@')
parser.add_argument('filename', nargs='?')
parser.add_argument('--foo', nargs='?', default=1)
parser.add_argument('--bar', nargs='?', default=1)
args = parser.parse_args()
print(args)
Run Code Online (Sandbox Code Playgroud)

args.txt

--foo
2
--bar
2
Run Code Online (Sandbox Code Playgroud)

样例用例

$ python script.py --foo 3
Namespace(bar=1, filename=None, foo='3')
$ python script.py @args.txt --foo 3
Namespace(bar='2', filename=None, foo='3')
Run Code Online (Sandbox Code Playgroud)

我原以为args.filename会保留文件名,但令人惊讶的是它具有值None。我知道我可以sys.argv通过一些处理来获取文件名。是否有一种更简洁的方法(理想情况下是argparse基于方法)来引出参数文件的名称?

101*_*owz 1

根据我的测试,使用fromfile_prefix_chars意味着 argparse 实际上不会将参数传递给您的程序。相反,argparse看到@args.txt,拦截它,从中读取,并将参数传递@args.txt给您的程序。这大概是因为大多数人并不真正需要文件名,只需要其中的参数,因此argparse可以省去创建另一个参数来存储不需要的东西的麻烦。

不幸的是,所有参数都作为局部变量存储在 中argparse.py,因此我们无法访问它们。我想你可以重写 argparse 的一些函数。请记住,这是一个可怕的、恶心的、hacky 的解决方案,我觉得解析sys.argv100% 更好。

from argparse import ArgumentParser

# Most of the following is copied from argparse.py
def customReadArgs(self, arg_strings):
    # expand arguments referencing files
    new_arg_strings = []
    for arg_string in arg_strings:

        # for regular arguments, just add them back into the list
        if not arg_string or arg_string[0] not in self.fromfile_prefix_chars:
            new_arg_strings.append(arg_string)

        # replace arguments referencing files with the file content
        else:
            try:
                fn = arg_string[1:]
                with open(fn) as args_file:

                    # What was changed: before was []
                    arg_strings = [fn]

                    for arg_line in args_file.read().splitlines():
                        for arg in self.convert_arg_line_to_args(arg_line):
                            arg_strings.append(arg)
                    arg_strings = self._read_args_from_files(arg_strings)
                    new_arg_strings.extend(arg_strings)
            except OSError:
                err = _sys.exc_info()[1]
                self.error(str(err))

    # return the modified argument list
    return new_arg_strings
ArgumentParser._read_args_from_files = customReadArgs
parser = ArgumentParser(fromfile_prefix_chars='@')
parser.add_argument('filename', nargs='?')
parser.add_argument('--foo', nargs='?', default=1)
parser.add_argument('--bar', nargs='?', default=1)
args = parser.parse_args()
print(args)
Run Code Online (Sandbox Code Playgroud)