如何从Python ConfigParser .items()中排除DEFAULTs?
我正在使用ConfigParser从一个配置文件中加载数据,具体如下:
test.conf:
[myfiles]
fileone: %(datadir)s/somefile.foo
filetwo: %(datadir)s/nudderfile.foo
load.py:
import ConfigParser
config = ConfigParser.ConfigParser({'datadir': '/tmp'})
config.read('test.conf')
print config.items('myfiles')
print config.get('myfiles', 'datadir')
输出结果:
$ python load.py
[('datadir', '/tmp'), ('filetwo', '/tmp/nudderfile.foo'), ('fileone', '/tmp/somefile.foo')]
/tmp
我很惊讶,变量替换的默认值 ('datadir', '/tmp')
竟然出现在 .items()
和 .get()
的结果中,就好像它们是配置文件中的值一样。这种情况是正常的吗?有没有什么方法可以让我在使用 .items()
时,不把这些默认值也算进去,但仍然能使用变量替换的功能呢?
参考链接: http://docs.python.org/library/configparser.html
谢谢!
更新: 有人指出这是正常的行为:默认值就像配置文件中的其他名称/值对一样。同时,配置文件中的名称/值对也可以进行“魔法替换”,所以如果我定义:
foo: bar
zap: %(foo)snowl
我会得到 [... ('zap': 'barnowl')]
这挺不错的,但我还是在想我能否实现我的目标:遍历配置文件中的名称/值对,进行变量替换,但不包括默认值。
我的具体情况是这样的:我想用类似 {basedir: '/foo/bar'}
的内容来初始化配置对象,因为某些文件的绝对路径会因安装而异。然后我需要把这个配置对象传递给其他类,让它们遍历这些文件。我不希望每个读取配置的类都知道它是用某些默认值初始化的,并且应该忽略这些默认值,因为它们并不是实际的文件。这可能吗?有没有办法在 .item()
和 .get()
中隐藏默认值,但仍然能进行变量替换呢?谢谢!
5 个回答
难道你不能把默认值过滤掉吗?
比如说:
filtered_items = [x for x in config.items('myfiles') if x[0] not in config.defaults()]
我特意注册了一个账号来回答这个问题。因为在我搜索的时候,这个问题在谷歌上是最热门的。
我深入研究了ConfigParser的源代码,找到了我认为简单又有效的解决方案。
在RawConfigParser
类(ConfigParser
继承自这个类)中,有一个叫default_section
的关键字参数。我通过以下方式实例化,成功忽略了配置中的DEFAULT部分:
from configparser import ConfigParser
parser = ConfigParser(default_section=None)
希望这也能帮助到其他人。
一般来说,我发现 configparser.Configparser 这个类非常有用,但也有一些不足之处。其他人也有类似的看法。
不过,它是可以被继承和扩展的,有时候效果不错,有时候就不太好(这很依赖具体的实现方式)。
这里有一个解决你问题的方法,已经在 Python3 中测试过了:
class ConfigParser(configparser.ConfigParser):
"""Can get options() without defaults
"""
def options(self, section, no_defaults=False, **kwargs):
if no_defaults:
try:
return list(self._sections[section].keys())
except KeyError:
raise NoSectionError(section)
else:
return super().options(section, **kwargs)
这是一个不太好的例子,因为它部分地复制了 options() 的源代码。要是 configparser 的基础类 RawConfigParser
能提供一个内部获取选项的函数 _options(self, section)
,并且能处理异常,那就更好了。然后再提供一个 options()
来使用这个函数。这样在继承的时候,我们就可以重用 _options()
了。
对于 Python 2,我认为唯一需要改动的就是 super()
的调用,改成 super(ConfigParser,self)
。
然后你可以使用:
print config.options('myfiles', no_defaults=True)
还可以用这个列表来进行迭代。