Python的ConfigParser每个部分唯一键
我看了文档的一部分,发现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 个回答
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
...
如果你不需要分段,这种方法会很有用。
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,它本身就支持将列表作为值类型。