【问题标题】:Python Config Parser (Duplicate Key Support)Python 配置解析器(重复密钥支持)
【发布时间】:2011-07-20 17:59:02
【问题描述】:

所以我最近开始为我正在处理的 Python 项目编写配置解析器。我最初避免使用 configparser 和 configobj,因为我想支持这样的配置文件:

key=value
key2=anothervalue

food=burger
food=hotdog
food=cake icecream

简而言之,这个配置文件将经常通过命令行通过 SSH 进行编辑。所以我不想制表符或挑剔间距(如 YAML),但我也希望避免在 vi 中换行具有多个值(很容易 10 或更多)的键。这就是为什么我想支持重复键。

在我的理想世界中,当我向 Python 配置对象询问食物时,它会给我一个带有 ['burger', 'hotdog', 'cake', 'icecream'] 的列表。如果没有定义食物值,它会查看默认配置文件并给我那个/那些值。

以上我已经实现了

然而,当我意识到我想要支持保留内联 cmets 等时,我的麻烦就开始了。我处理读取和写入配置文件的方式是将文件解码为内存中的字典,从字典中读取值,或将值写入字典,然后将该字典转储回文件中。这对于保留行顺序和评论等来说并不是很好,而且它让我大吃一惊。

A) ConfigObj 看起来拥有我需要的一切,除了支持重复键。相反,由于换行,它希望我制作一个列表,在 vi 中通过 ssh 手动编辑会很痛苦。我可以让 configobj 对 ssh/vi 更友好吗?

B) 我的自制解决方案有问题吗?有没有更好的方法来读取/写入/存储我的配置值?是否有任何简单的方法可以通过修改该行并从内存中重写整个配置文件来处理更改配置文件中的键值?

【问题讨论】:

    标签: python configuration yaml config


    【解决方案1】:

    如果可以的话,我当然会尝试利用标准库中的内容。

    配置解析器类的签名如下所示:

    class ConfigParser.SafeConfigParser([defaults[, dict_type[, allow_no_value]]])

    注意dict_type 参数。提供时,它将用于为部分列表、部分中的选项和默认值构造字典对象。默认为collections.OrderedDict。也许您可以在其中传递一些东西以获得您想要的多键行为,然后获得ConfigParser 的所有优势。您可能必须编写自己的类来执行此操作,或者您可能会在 PyPi 或 ActiveState 食谱中找到为您编写的类。尝试寻找包或多集类。

    我要么走那条路,要么干脆把它列个清单:

    foo = value1, value2, value3
    

    【讨论】:

    • 我试过了,失败了,主要是因为 RawConfigParser 的 _read 方法使用同一个字典来解析多行值,将它们写在一个列表中作为键的映射对象。最后再做一遍以加入字典中的所有内容。所以你最终会得到类似{'key': ['value'], 'key': 'value'} 的东西,并且需要一个非常糟糕的 hack 才能让它工作。
    【解决方案2】:

    疯狂的想法:将您的字典值作为包含行号、列号和值本身的 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() 
    

    【讨论】:

    • 你需要另一个函数来为字典增加价值
    猜你喜欢
    • 2011-09-25
    • 2012-03-05
    • 2019-04-23
    • 1970-01-01
    • 1970-01-01
    • 2017-07-21
    • 2011-12-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多