如何从 Python ConfigParser .items() 中排除默认值?
Posted
技术标签:
【中文标题】如何从 Python ConfigParser .items() 中排除默认值?【英文标题】:How to exclude DEFAULTs from Python ConfigParser .items()? 【发布时间】:2011-01-12 10:56:17 【问题描述】:我正在使用 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() 的默认值但仍然有插值?谢谢!
【问题讨论】:
我无法理解为什么这是默认行为,更不用说为什么无法关闭它了。 【参考方案1】:以下内容应该只为您提供 myfiles 部分中的键/值对,而不列出 DEFAULT 中的那些:
list(set(config.items('myfiles'))-set(config.items('DEFAULT')))
【讨论】:
【参考方案2】:你不能只过滤掉默认值吗?
例如:
filtered_items = [x for x in config.items('myfiles') if x[0] not in config.defaults()]
【讨论】:
如果两者同名则不行。【参考方案3】:一般来说,我发现configparser.Configparser 类非常有用,但也缺乏。 Others have, too.
但是,它可以被子类化和扩展,有时很好,有时不太好(=非常依赖于实现)
以下是您的问题的解决方案,已在 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)
这是不好的例子之一,因为它部分复制了the source code 的options()
。如果 configparser 基类 RawConfigParser
将提供一个内部 getter 选项 _options(self, section)
将包含异常转换,并且 options()
将利用它,那就更好了。然后,在子类化中我们可以重用_options()
。
对于 Python 2,我相信唯一的变化是 super()
调用 super(ConfigParser,self)
。
然后您可以使用:
print config.options('myfiles', no_defaults=True)
并且还使用该列表进行迭代。
【讨论】:
你在正确的轨道上,但是他问的是 .items(),而不是 .options()。我认为这会让他到达那里。 我理解他的问题是如何“迭代我的配置文件中的名称/值对,使用变量插值,没有默认值。”这就是上面的代码所做的。对我来说,这是一个准确的答案。不幸的是,通常情况下,问题的发布者似乎并不活跃。否则,我们可以让他决定这是否可以作为答案。 是的,这个问题一直存在,需要重点关注。他在代码和最后一句中使用了 .items。他要求 name/val 对,这就是 .items 所做的。选项只返回键。您的回答帮助我覆盖 .items 非常感谢。 在 Python2 中,super
根本不起作用,因为ConfigParser
是一个老式类。 (是的,真的。)
另外,请注意 self._sections[section].keys()
(至少在 Python 2 中)在除 DEFAULTSECT
之外的每个部分中都包含一个名为 __name__
的条目; options
的默认实现不包含此条目,因此可能应该在此处明确排除它。【参考方案4】:
试试这个:
config = ConfigParser.ConfigParser('blahblahblah': 'blah')
config.read('test.conf')
blahblahblah
键也将出现在items
中,不是因为它是 .ini 文件中的模板,而是因为您将其指定为默认值。这就是 ConfigParser 处理默认值的方式:如果在文件中找不到它们,它会分配它们的默认值。
所以在我看来,您在这里有一个简单的概念混淆。
【讨论】:
感谢您的澄清。因此,默认字典 both 用于为某些键提供默认值,以及嵌入在配置文件中的变量的“魔术插值”。此外,配置文件中定义的变量也用于“魔术插值”,所以如果我定义: foo: bar zap: %(foo)snowl 我会得到 [... ('zap': 'barnowl')]这非常简洁,但我仍然想知道我是否可以完成我想要完成的事情:迭代我的配置文件中的名称/值对,使用变量插值,没有默认值。以上是关于如何从 Python ConfigParser .items() 中排除默认值?的主要内容,如果未能解决你的问题,请参考以下文章
python configparser 如何去除等号附近的空格
如何使用 configparser 更新值 python .ini 文件