Python的ConfigParser每个部分唯一键

9 投票
2 回答
15666 浏览
提问于 2025-04-11 20:29

我看了文档的一部分,发现ConfigParser会返回一个包含选项的键值对列表。我原以为在一个部分内,键不需要唯一,否则解析器就会返回一个映射。我是根据这个假设设计了我的配置文件格式,结果很遗憾地发现并不是这样:

>>> from ConfigParser import ConfigParser
>>> from StringIO import StringIO
>>> fh = StringIO("""
... [Some Section]
... spam: eggs
... spam: ham
... """)
>>> parser = ConfigParser()
>>> parser.readfp(fh)
>>> print parser.items('Some Section')
[('spam', 'ham')]

然后我又回去找到了我应该看的文档部分:

部分通常存储在一个内置字典中。可以将另一种字典类型传递给ConfigParser的构造函数。例如,如果传递一个会对键进行排序的字典类型,那么在写回时,部分和每个部分内的键都会被排序。

为了保持我现有的配置文件格式(我现在真的很喜欢这个格式;)我在考虑传递一个像映射一样的对象,正如上面提到的那样,它可以累积值而不是覆盖它们。有没有更简单的方法可以防止键值对的冲突呢?我是不是应该直接写一个ConfigParser的变体,而不是做一个复杂的适配器(这样如果ConfigParser的实现改变了可能会出问题)?

我觉得这可能是那种“真是太明显了”的时刻,我只看到了困难的解决方案。

[编辑:] 这是一个更具体的例子,说明我想多次使用相同的键:

[Ignored Paths]
ignore-extension: .swp
ignore-filename: tags
ignore-directory: bin

我不喜欢用逗号分隔的列表语法,因为当你有很多值时,这种方式看起来很难受;比如说,五十个扩展名的逗号分隔列表就特别难以阅读。

2 个回答

0

ConfigParser这个工具有一些不足之处,这就是为什么pyglet选择使用修改过的epydoc版本来替代ConfigParser的ini格式,而使用这种简单格式:

name: pyglet
url: http://www.pyglet.org/

output: html
target: doc/api/
...    
module: pyglet

exclude: pyglet.gl.gl
exclude: pyglet.gl.agl
exclude: pyglet.gl.lib_agl
exclude: pyglet.gl.wgl
...

如果你不需要分段,这种方法会很有用。

10

ConfigParser 这个工具并不是为了处理你这种情况而设计的。而且,我觉得你的配置文件有点不太合理。

ConfigParser 给你提供了一个类似字典的结构,每个部分都是这样。所以当你调用 parser.items(section) 的时候,我期待的结果应该和 dict.items() 类似,就是一系列的键/值对。我绝对不会期待看到这样的东西:

[('spam', 'eggs'), ('spam', 'ham')]

更不用说,你希望下面的内容怎么表现呢?:

parser.get('Some Section', 'spam')

这才是获取值的正确方式。

如果你想为同一个键存储多个值,我建议你在配置文件中这样写:

[Some Section]
spam: eggs, ham

然后在你的代码中这样使用:

spam_values = [v.strip() for v in parser.get('Some Section', 'spam').split(',')]

当然,这种方法只适用于值中不包含逗号的情况,或者你需要处理引号。如果有这种需求,你应该使用更高级的技巧(可以参考 这个这个)。

补充一下:如果你不介意多一个依赖,你可以看看 ConfigObj,它本身就支持将列表作为值类型。

撰写回答