我正在尝试使用argparse
模块。我正在处理 2 个配置文件:
1.默认 CFG 文件 2.文件由用户提供。
如果在运行时未提供任何文件,请从默认文件读取。如果用户提供文件,请使用提供文件的内容。
我的问题是:我想为每个parser.add_agument
提供default
字段,所以如果用户没有提供,它将始终具有一些默认值。这些值可以从任一文件(即默认文件或用户给定文件(中读取。我需要检查提供了哪个文件,然后from default/user-given-file import *
我的代码:
get_args.py
class GetArgs:
def get_args(self):
parser = argparse.ArgumentParser(description='foo')
#
parser.add_argument(
'-c', '--config', type=str, help='Provide a file',
required=False, default='settings.cfg')
#now note that below "default=version" will be from either "settings.cfg" or "user given file"
# here may be i need to import from file ?
parser.add_argument(
'-v','--version', type=str, help='API version', required=False, default=version)
args = parser.parse_args()
# Assign args to variables
config=args.config
version = args.version
retutn config,version
读取 CFG 文件的代码:read_file.py
import ConfigParser
configParser = ConfigParser.RawConfigParser()
configParser.read(file)
try:
version= configParser.get('Set', 'version')
....
....
except ConfigParser.NoOptionError:
print "Option not found in configuration file!"
sys.exit(1)
像这样:
1.python get_args.py #reads "version" from settings.cfg
2.python get_args.py --config /path/to/file/file.cfg #reads "version" file.cfg
当我不提供 --config 时,它工作得很好。
这可以动态阅读吗?
动态填充解析器
今天的另一个问题得到了一个答案,显示了如何从字典中的值填充解析器:https://stackoverflow.com/a/35132772/901925
Ipython做了类似的事情。 它读取配置文件(默认文件以及用户配置文件(,并使用配置值来流行解析器。 这为用户提供了几个级别的控制 - 默认配置,配置文件配置,最后是命令行。 但是Ipython代码相当复杂。
编辑参数值
另一个有用的点是,每个参数或 Action 对象在创建后都可用,并且可以(在限制范围内(被修改。
arg1 = parser.add_argument('--foo', default='test', ...)
# arg1 is an Action object with the various parameters
print arg1 # a display of some attributes
print arg1.default # the value of the default as set above
arg1.default = 'different' # assign a new value
因此,可以在解析之前动态设置默认值。
前缀字符文件
另一个有用的工具是 https://docs.python.org/3/library/argparse.html#fromfile-prefix-chars
parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
允许我指定以字符开头的文件的名称。 它将读取文件内容并将字符串拼接到sys.argv
列表中,就像我键入它们一样。
解析后填写默认值
但是,如果要在命令行中指定配置文件,然后使用其内容设置解析器的默认值,则事情会变得更加复杂。
解析后args
将是一个命名空间对象,其中包含配置文件名称以及它解析的所有其他参数。
您可以使用print args
或字典形式查看args
的确切内容vars(args)
。 没有关于哪些值是使用解析器默认值
最干净的默认值解析后测试是
if args.foo is None:
# this has the default default
如果值None
则只能来自默认值,而不能来自命令行(没有转换为 None
的字符串(。
所以我可以想象写一个函数来迭代vars(args)
键,测试None
,并将其替换为config
中的相应值。 (你需要帮助吗?
如果config
和args
都转换为兼容的字典,则可以使用字典update
方法将值从一个传输到另一个。
default=argparse.SUPPRESS
可用于在参数未出现在命令行中时将参数保留在命名空间之外。 https://docs.python.org/3/library/argparse.html#default。 这可以与字典更新一起使用,例如
config_dict.update(vars(args))
只会更改命令行中给出的参数的config_dict
。
两级解析器
另一个想法是使用两阶段解析。 定义一个具有config_file
参数的解析器,而不定义(或很少(其他参数。 使用 parse_known_args
运行它以获取 config_file
值。 读取配置文件并使用它来填充第二阶段解析器(或至少修改其默认值(。 现在运行第二阶段解析器以获取完整的命名空间(我只是忽略此参数中的任何config_file
值(。
链图
https://docs.python.org/3/library/collections.html#chainmap-examples-and-recipes
一个新的collections
类,ChainMap
有一个从命名空间、env、默认值等进行链式值查找的示例。
namespace = parser.parse_args()
command_line_args = {k:v for k, v in vars(namespace).items() if v}
combined = ChainMap(command_line_args, os.environ, defaults)
print(combined['color'])
使用 argparse 时从环境变量设置选项的其他好主意