ConfigParser生成的典型文件如下所示:

[Section]
bar=foo
[Section 2]
bar2= baz

现在,有没有一种方法来索引列表,例如:

[Section 3]
barList={
    item1,
    item2
}

相关问题:Python的ConfigParser每个节的唯一键


当前回答

我过去也遇到过同样的问题。如果需要更复杂的列表,可以考虑通过继承ConfigParser来创建自己的解析器。然后你会用它覆盖get方法:

    def get(self, section, option):
    """ Get a parameter
    if the returning value is a list, convert string value to a python list"""
    value = SafeConfigParser.get(self, section, option)
    if (value[0] == "[") and (value[-1] == "]"):
        return eval(value)
    else:
        return value

有了这个解决方案,您还可以在配置文件中定义字典。

但是要小心!这并不安全:这意味着任何人都可以通过您的配置文件运行代码。如果安全性在你的项目中不是问题,我会考虑直接使用python类作为配置文件。下面的文件比ConfigParser文件更强大、更可消耗:

class Section
    bar = foo
class Section2
    bar2 = baz
class Section3
    barList=[ item1, item2 ]

其他回答

import ConfigParser
import os

class Parser(object):
    """attributes may need additional manipulation"""
    def __init__(self, section):
        """section to retun all options on, formatted as an object
        transforms all comma-delimited options to lists
        comma-delimited lists with colons are transformed to dicts
        dicts will have values expressed as lists, no matter the length
        """
        c = ConfigParser.RawConfigParser()
        c.read(os.path.join(os.path.dirname(__file__), 'config.cfg'))

        self.section_name = section

        self.__dict__.update({k:v for k, v in c.items(section)})

        #transform all ',' into lists, all ':' into dicts
        for key, value in self.__dict__.items():
            if value.find(':') > 0:
                #dict
                vals = value.split(',')
                dicts = [{k:v} for k, v in [d.split(':') for d in vals]]
                merged = {}
                for d in dicts:
                    for k, v in d.items():
                        merged.setdefault(k, []).append(v)
                self.__dict__[key] = merged
            elif value.find(',') > 0:
                #list
                self.__dict__[key] = value.split(',')

所以现在我的config.cfg文件,看起来像这样:

[server]
credentials=username:admin,password:$3<r3t
loggingdirs=/tmp/logs,~/logs,/var/lib/www/logs
timeoutwait=15

可以解析为我的小项目所需的足够细粒度的对象。

>>> import config
>>> my_server = config.Parser('server')
>>> my_server.credentials
{'username': ['admin'], 'password', ['$3<r3t']}
>>> my_server.loggingdirs:
['/tmp/logs', '~/logs', '/var/lib/www/logs']
>>> my_server.timeoutwait
'15'

这是为了非常快速地解析简单的配置,您失去了获取int、bool和其他类型输出的所有能力,既没有转换从Parser返回的对象,也没有重新执行Parser类在其他地方完成的解析工作。

没有什么可以阻止您将列表打包到一个带分隔符的字符串中,然后在从配置中获得字符串后将其解包。如果你这样做,你的配置部分看起来像:

[Section 3]
barList=item1,item2

它并不漂亮,但对于大多数简单的列表来说,它是有用的。

我使用ConfigParser和JSON的组合:

[Foo]
fibs: [1,1,2,3,5,8,13]

只需阅读:

>>> json.loads(config.get("Foo","fibs"))
[1, 1, 2, 3, 5, 8, 13]

如果你的列表很长,你甚至可以断行(谢谢@peter-smit):

[Bar]
files_to_check = [
     "/path/to/file1",
     "/path/to/file2",
     "/path/to/another file with space in the name"
     ]

当然,我可以只使用JSON,但我发现配置文件更可读,和[DEFAULT]部分非常方便。

为了进一步理解Grr的答案(我最喜欢的答案),您可以使用map函数,而不是在.ini文件中用引号括住列表项。这允许您以python方式指定列表项数据类型。

配置文件:

[section]
listKey1: 1001, 1002, 1003
listKey2: AAAA, BBBB, CCCC

代码:

cfgFile = 'config.ini'
parser = ConfigParser(converters={'list': lambda x: [i.strip() for i in x.split(',')]})
parser.read(cfgFile)

list1 = list(map(int, parser.getlist('section', 'listKey1')))
list2 = list(map(str, parser.getlist('section', 'listKey2')))

print(list1)
print(list2)

输出:

[1001, 1002, 1003]
['AAAA', 'BBBB', 'CCCC']

如果这是你的config.ini:

[Section 3]
barList=item1,item2

然后使用configparser你可以这样做:

from configparser import ConfigParser
config = ConfigParser()
config.read('config.ini')
my_list = config['Section 3']['barList'].split(',')

你会得到:

 my_list =  ['item1', 'item2']

split()方法将返回一个列表,参见Python字符串文档。

如果你在config.ini中有空格,像这样:

[Section 3]
barList= item1, item2

那你最好这样做:

my_list = [x.strip() for x in config['Section 3']['barList'].split(',')]

如果你的项目是数字(例如整数),只需应用:

my_list_of_ints = list(map(int, my_list))

你会得到:

my_list_of_ints =  [item1, item2]