使用ConfigParser从ini文件中读取数组

时间:2014-01-22 05:43:41

标签: php python arrays ini

我已阅读此post,并在subscriber.ini中定义了一个数组

[smtp]
subscriber[] = aaa@hotmail.com
subscriber[] = bbb@XX.webmail
subscriber[] = ccc@test.org

然后我尝试使用ConfigParser来读取数组

#!/usr/bin/python
import ConfigParser

CONFIG_FILE = 'subscriber.ini'

config = ConfigParser.ConfigParser()
config.read( CONFIG_FILE )

subscriber = config.get('smtp' , 'subscriber[]' )
print subscriber 

它将输出最后一个元素ccc@test.org。但我希望有一个完整的用户名单。

如何从ini文件中获取数组?

3 个答案:

答案 0 :(得分:5)

subscriber[]自动将subscriber变为多个值列表的语法一般不是.ini文件的功能,也不是ConfigParser的功能。它是Zend_Config_Ini的一个特征。

在Python中,ConfigParser ini文件创建一个dict,将每个键映射到其值。如果您有多个值,它将覆盖以前的值。神奇的[]后缀毫无意义。

但是,ConfigParser构造函数允许您指定自定义字典类型或工厂,而不是默认的OrderedDict

一个简单的解决方案是使用defaultdict(list)(或OrderedDefaultDict,其中有文档中的配方)用于底层存储,__setitem__(self, key, value)执行self.dd[key].append(value)和委托一切正常。 (或者,如果您愿意,继承自defaultdict,则覆盖构造函数以将list传递给超级,然后只是不要覆盖除__setitem__之外的任何内容。)这将使将所有值列入列表。

你甚至可以做一些hacky,其中只有一次看到的值是单个值,但如果再次看到相同的名称,它就会成为一个列表。我认为这将是一个糟糕的想法(你真的想检查config.get('smtp', 'subscriber[]')的类型来决定你是否要迭代它吗?),但如果你愿意,How to ConfigParse a file keeping multiple values for identical keys?显示如何

然而,重复你正在寻找的确切魔法并不是很难,其中以[]结尾的所有键都是列表(无论它们出现一次还是多次),其他一切都像普通一样(如果多次出现,则仅保留最后一个值)。像这样:

class MultiDict(collections.OrderedDict):
    def __setitem__(self, key, value):
        if key.endswith('[]'):
            super(MultiDict, self).setdefault(key, []).append(value)
        else:
            super(MultiDict, self).__setitem__(key, value)

这显然不会提供Zend_Config_Ini在普通.ini文件之上添加的扩展功能的所有。例如,[group : subgroup : subsub]作为组名称没有任何特殊含义,key.subkey.subsub也不会作为键名。 PHP值TRUEFALSEyesnoNULL不会转换为Python值True,{{1} },FalseTrueFalse。数字不会神奇地成为数字。 (实际上,这不是None的一个特征,而是PHP错误输入的错误。)你必须使用Zend_Config_Ini条评论,而不是自由地混合#,{{1} }和#。等等。您要添加的任何功能都必须手动添加,就像您执行此操作一样。

正如我在评论中所建议的那样,如果你真的想拥有两个以上的层次结构,那么你可能会更好地使用自然无限分层的格式,其中任何值都可以是其他值的列表或字典。< / p>

JSON现在无处不在。它可能不像INI那样具有人类可编辑性,但我认为2014年有更多人比INI更熟悉它。它具有巨大的优势,它是标准化格式,Python(2.6+)和PHP(5.2) +)在标准库中附带解析器和漂亮的打印机。

YAML是一种更灵活,人性化的格式。但是您需要使用这两种语言的第三方模块(请参阅YAML网站上的列表)。如果你不小心,它也会带来一些安全问题。 (请参阅;文档中的//和朋友;大多数其他图书馆都有相似的功能。)

答案 1 :(得分:4)

Python ConfigParser不提供此功能。请改用以下代码:

[smtp]
subscriber = aaa@hotmail.com bbb@XX.webmail ccc@test.org

然后在你的剧本中:

subscriber = config.get('smtp' , 'subscriber').split()

答案 2 :(得分:1)

我想知道你是否考虑过使用Michael Foord的configobj module?它似乎有能力 做你想做的事情,试图阻止ConfigParser做你显然需要的事情可能会更好。