所以我最近开始为我正在研究的Python项目编写一个配置解析器。我最初避免使用configparser和configobj,因为我想支持这样的配置文件:
key=value
key2=anothervalue
food=burger
food=hotdog
food=cake icecream
简而言之,这个配置文件将经常通过SSH命令行进行编辑。因此我不想对间距进行制表或挑剔(如YAML),但我也希望避免使用多个值(容易10个或更多)的行在vi中换行。这就是我想支持重复键的原因。
一个我的理想世界,当我向Python配置对象询问食物时,它会给我一个回复列表['burger','hotdog','cake','icecream']。如果没有定义食物值,它会查看默认配置文件并给我/那些值。
我已经实施了上述
然而,当我意识到我想支持保留内联评论等时,我的麻烦就开始了。我处理读取和写入配置文件的方式是将文件解码为内存中的dict,读取dict中的值,或将值写入dict,然后将该dict转储回文件。这对于保留行顺序和评论等并不是很好,而且它正在惹恼我。
A)ConfigObj看起来像我需要的一切,除了支持重复键。相反,它希望我制作一个列表,由于换行,在vi上通过ssh手动编辑会很麻烦。我可以使configobj更ssh / vi友好吗?
B)我的自制软件解决方案有问题吗?有没有更好的方法来读/写/存储我的配置值?有没有简单的方法来处理更改配置文件中的键值,只需修改该行并从内存中重写整个配置文件?
答案 0 :(得分:0)
疯狂的想法:将您的字典值作为包含行号,列号和值本身的3元组列表,并添加特殊键以供评论。
CommentSymbol = ';'
def readConfig(filename):
f = open(filename, 'r')
if not f:
return
def addValue(dict, key, lineIdx, colIdx, value):
if key in dict:
dict[key].append((lineIdx, colIdx, value))
else:
dict[key] = [(lineIdx, colIdx, value)]
res = {}
i = 0
for line in f.readlines():
idx = line.find(CommentSymbol)
if idx != -1:
comment = line[idx + 1:]
addValue(res, CommentSymbol, i, idx, comment)
line = line[:idx]
pair = [x.strip() for x in line.split('=')][:2]
if len(pair) == 2:
addValue(res, pair[0], i, 0, pair[1])
i += 1
return res
def writeConfig(dict, filename):
f = open(filename, 'w')
if not f:
return
index = sorted(dict.iteritems(), cmp = lambda x, y: cmp(x[1][:2], y[1][:2]))
i = 0
for k, V in index:
for v in V:
if v[0] > i:
f.write('\n' * (v[0] - i - 1))
if k == CommentSymbol:
f.write('{0}{1}'.format(CommentSymbol, str(v[2])))
else:
f.write('{0} = {1}'.format(str(k), str(v[2])))
i = v[0]
f.close()
答案 1 :(得分:0)
如果可以的话,我当然会尝试利用标准库中的内容。
配置解析器类的签名如下所示:
class ConfigParser.SafeConfigParser([defaults[, dict_type[, allow_no_value]]])
注意dict_type
参数。提供时,这将用于构造节的列表,节的选项和默认值的字典对象。它默认为collections.OrderedDict
。也许你可以在那里传递一些东西来获得你想要的多键行为,然后获得ConfigParser
的所有优点。您可能必须编写自己的类才能执行此操作,或者您可能会在PyPi或ActiveState配方中找到一个为您编写的类。尝试寻找包或多重课程。
我要么走这条路,要么只是把它拿出来制作清单:
foo = value1, value2, value3