Python argparse 的动态参数

12 投票
2 回答
12439 浏览
提问于 2025-04-18 17:20

我在Python中需要动态创建一个参数列表。我写了一个脚本来演示这个功能,叫做args.py,下面是代码:

#!/usr/bin/python
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-args_file', default = 'args.txt')

with open(parser.parse_args().args_file, 'r') as f:
    args = f.readlines()

for arg in args:
    parser.add_argument('-' + arg.strip())

dynamic_args = parser.parse_args()

print dynamic_args

我在同一个文件夹里还有一个文本文件,叫做args.txt,下面是这个文件的内容:

arg1
arg2
arg3

正如预期的那样,运行args.py而不带任何参数会得到:

Namespace(arg1=None, arg2=None, arg3=None, args_file='args.txt')

不过,我遇到的问题是,当我用-h这个参数运行我的脚本时,我希望能显示在args_file中找到的参数,像下面这个例子:

usage: args.py [-h] [-args_file ARGS_FILE] [-arg1 ARG1] [-arg2 ARG2]
               [-arg3 ARG3]

但实际上我看到的是:

usage: args.py [-h] [-args_file ARGS_FILE]

而且,如果我以交互模式运行这个脚本(也就是用命令python -i arg.py),然后在交互提示符下输入命令"parser.print_usage()",我能得到想要的结果(显示出 -argN 参数)。另外,输入"arg.py -arg1 1"或者"arg.py arg1 1"都会出现"unrecognized arguments"的错误。

我尝试了我能想到的所有方法,但到目前为止都没有成功。有没有Python高手能给我一些建议?

2 个回答

2

根据Hazen的回答,使用parents这个选项会更简单。

https://docs.python.org/3/library/argparse.html#parents

import argparse
argfile_parser = argparse.ArgumentParser(add_help=False)
argfile_parser.add_argument('-args_file', default = 'args.txt')
full_parser = argparse.ArgumentParser(parents=[argfile_parser])
with open(argfile_parser.parse_known_args()[0].args_file, 'r') as f:
    for arg in f:
        full_parser.add_argument('-' + arg.strip())

dynamic_args = full_parser.parse_args()

print dynamic_args
14

正如Martjin提到的,第一次解析时可以不需要解析器的帮助。另一个做法是第一次使用parse_known_args,这样你只解析args_file。

在这种情况下,我喜欢用一个临时的解析器来进行第一次解析,然后用一个完整的解析器来进行最终的解析,这样可以保持清晰:

import argparse
argfile_parser = argparse.ArgumentParser(add_help=False)
full_parser = argparse.ArgumentParser()
argfile_parser.add_argument('-args_file', default = 'args.txt')
full_parser.add_argument('-args_file', default = 'args.txt')
with open(argfile_parser.parse_known_args()[0].args_file, 'r') as f:
    for arg in f:
        full_parser.add_argument('-' + arg.strip())

dynamic_args = full_parser.parse_args()

print dynamic_args

为了测试,我添加了一个文件args2.txt

argA
argB
argC

我觉得结果就是你想要的:

lap:~$ python tmp.py -h
usage: tmp.py [-h] [-args_file ARGS_FILE] [-arg1 ARG1] [-arg2 ARG2]
              [-arg3 ARG3]

optional arguments:
  -h, --help            show this help message and exit
  -args_file ARGS_FILE
  -arg1 ARG1
  -arg2 ARG2
  -arg3 ARG3
lap:~$ python tmp.py -args_file args2.txt
Namespace(argA=None, argB=None, argC=None, args_file='args2.txt')
lap:~$ python tmp.py -h -args_file args2.txt
usage: tmp.py [-h] [-args_file ARGS_FILE] [-argA ARGA] [-argB ARGB]
              [-argC ARGC]

optional arguments:
  -h, --help            show this help message and exit
  -args_file ARGS_FILE
  -argA ARGA
  -argB ARGB
  -argC ARGC
lap:~$ python tmp.py -arg1 foo
Namespace(arg1='foo', arg2=None, arg3=None, args_file='args.txt')
lap:~$ python tmp.py -args_file args2.txt -argA bar
Namespace(argA='bar', argB=None, argC=None, args_file='args2.txt')

撰写回答