将ConfigParser.items('')转换为字典


67

如何将ConfigParser.items('section')的结果转换为字典以格式化字符串,如下所示:

import ConfigParser

config = ConfigParser.ConfigParser()
config.read('conf.ini')

connection_string = ("dbname='%(dbname)s' user='%(dbuser)s' host='%(host)s' "
                     "password='%(password)s' port='%(port)s'")

print connection_string % config.items('db')

5
请小心使用_sections:此文档未记录,因此不能保证在未来的python版本中可以使用
— Bertera 2011年

1
这对python 2有效,但是如果您使用的是python 3,则可以将下标的配置解压缩为format()。“您的{pattern}”。format(** config ['db'])
— Hovis Biddle 2015年

Answers:


63

实际上,您已经在中完成了此操作config._sections。例:

$ cat test.ini
[First Section]
var = value
key = item

[Second Section]
othervar = othervalue
otherkey = otheritem

接着:

>>> from ConfigParser import ConfigParser
>>> config = ConfigParser()
>>> config.read('test.ini')
>>> config._sections
{'First Section': {'var': 'value', '__name__': 'First Section', 'key': 'item'}, 'Second Section': {'__name__': 'Second Section', 'otherkey': 'otheritem', 'othervar': 'othervalue'}}
>>> config._sections['First Section']
{'var': 'value', '__name__': 'First Section', 'key': 'item'}

编辑: 我同样的问题溶液downvoted所以我会进一步说明我的答案是如何做同样的事情,而不必直通部分dict(),因为config._sections是由模块为您已经提供。

示例test.ini:

[db]
dbname = testdb
dbuser = test_user
host   = localhost
password = abc123
port   = 3306

发生的魔法:

>>> config.read('test.ini')
['test.ini']
>>> config._sections
{'db': {'dbname': 'testdb', 'host': 'localhost', 'dbuser': 'test_user', '__name__': 'db', 'password': 'abc123', 'port': '3306'}}
>>> connection_string = "dbname='%(dbname)s' user='%(dbuser)s' host='%(host)s' password='%(password)s' port='%(port)s'"
>>> connection_string % config._sections['db']
"dbname='testdb' user='test_user' host='localhost' password='abc123' port='3306'"

因此,这种解决方案没有错,实际上只需要少一步。感谢您的光临!


3
我并不是说这是错误的,但是我不能使用它,因为我使用配置解析器内置的替换%(syntax)s对其进行了测试。在不知道的情况下,这允许在其他配置值中使用配置值。这些不会在_sections成员中扩展,而是通过items()函数扩展。
— AlwaysTraining 2013年

59
使用_sections很危险。没有在API中公开,也不是将来的证明。
— johnharris85 2013年

38
这是一个私有API和糟糕的建议。
— acdx

11
如果有人决定更改内部工作方式,那么遵循此建议的任何人都会使ConfigParser的维护人员的生活变得更加艰辛,令人沮丧的是,人们建议使用私有API
— 2015年

7
大家冷静一下 已经六年了,API尚未更改。现在,如果以及何时公共API真正提高了用户友好性,我将更新此答案。
— jathanism

99

你有没有尝试过

print connection_string % dict(config.items('db'))

?


对。这对我有用,虽然获得批准的某种方式没有..也许这是Python版本的东西..
— Ricky Levi 2014年

10
@Ricky,我猜该用户不应该访问_sections。
— Dacav 2014年

70

我是如何做到这一点的?

my_config_parser_dict = {s:dict(config.items(s)) for s in config.sections()}

仅是其他答案,但当它不是您的方法的真正业务,而您只需要在一个地方使用它时,使用较少的行即可,并利用dict理解的力量可能会有用。


3
优雅而便携。
— Jacob Lee

@DanielBraun:我相信詹姆斯·凯尔的答案更正确。
— martineau

喜欢这个答案。
— SW_user2953243

1
这确实应该是公认的答案。这提供了一个非常Python化的解决方案,而无需访问私有属性。
— 亚伦·西福

19

我知道很久以前就问过这个问题,并且选择了一个解决方案,但是选择的解决方案没有考虑默认值和变量替换。由于它是从解析器中搜索创建字典时的第一击,因此我想发布我的解决方案,该解决方案包括使用ConfigParser.items()的默认替换和变量替换。

from ConfigParser import SafeConfigParser
defaults = {'kone': 'oneval', 'ktwo': 'twoval'}
parser = SafeConfigParser(defaults=defaults)
parser.set('section1', 'kone', 'new-val-one')
parser.add_section('section1')
parser.set('section1', 'kone', 'new-val-one')
parser.get('section1', 'ktwo')
parser.add_section('section2')
parser.get('section2', 'kone')
parser.set('section2', 'kthree', 'threeval')
parser.items('section2')
thedict = {}
for section in parser.sections():
    thedict[section] = {}
    for key, val in parser.items(section):
        thedict[section][key] = val
thedict
{'section2': {'ktwo': 'twoval', 'kthree': 'threeval', 'kone': 'oneval'}, 'section1': {'ktwo': 'twoval', 'kone': 'new-val-one'}}

执行此操作的便捷功能可能类似于:

def as_dict(config):
    """
    Converts a ConfigParser object into a dictionary.

    The resulting dictionary has sections as keys which point to a dict of the
    sections options as key => value pairs.
    """
    the_dict = {}
    for section in config.sections():
        the_dict[section] = {}
        for key, val in config.items(section):
            the_dict[section][key] = val
    return the_dict

7

对于单个部分,例如“常规”,您可以执行以下操作:

dict(parser['general'])

这是读取基于配置的数据库配置的最简单的解决方案。[我相信] SzymonLipiński想要达到的目标。
— WHS

2

这是使用Python 3.7withconfigparser和的另一种方法ast.literal_eval:

game.ini

[assets]
tileset = {0:(32, 446, 48, 48), 
           1:(96, 446, 16, 48)}

game.py

import configparser
from ast import literal_eval

config = configparser.ConfigParser()
config.read('game.ini')

# convert a string to dict
tileset = literal_eval(config['assets']['tileset'])

print('tileset:', tileset)
print('type(tileset):', type(tileset))

输出

tileset: {0: (32, 446, 48, 48), 1: (96, 446, 16, 48)}
type(tileset): <class 'dict'>

2

将Michele d'Amico和Kyle的答案(无字典)结合在一起,会产生较不易读但引人注目的内容:

{i: {i[0]: i[1] for i in config.items(i)} for i in config.sections()}

2

另一种选择是:

config.ini

[DEFAULT]
potato=3

[foo]
foor_property=y
potato=4


[bar]
bar_property=y

解析器

import configparser
from typing import Dict


def to_dict(config: configparser.ConfigParser) -> Dict[str, Dict[str, str]]:
    """
    function converts a ConfigParser structure into a nested dict
    Each section name is a first level key in the the dict, and the key values of the section
    becomes the dict in the second level
    {
        'section_name': {
            'key': 'value'
        }
    }
    :param config:  the ConfigParser with the file already loaded
    :return: a nested dict
    """
    return {section_name: dict(config[section_name]) for section_name in config.sections()}

main.py

import configparser

from parser import to_dict


def main():
    config = configparser.ConfigParser()
    # By default section names are parsed to lower case, optionxform = str sets to no conversion.
    # For more information: https://docs.python.org/3/library/configparser.html#configparser-objects
    # config.optionxform = str
    config.read('config.ini')
    print(f'Config read: {to_dict(config)}')
    print(f'Defaults read: {config.defaults()}')


if __name__ == '__main__':
    main()

1

在Python +3.6中,您可以执行此操作

file.ini

[SECTION1]
one = 1
two = 2

[SECTION2]
foo = Hello
bar = World

[SECTION3]
param1 = parameter one
param2 = parameter two

file.py

import configparser

cfg = configparser.ConfigParser()
cfg.read('file.ini')
# Get one section in a dict
numbers = {k:v for k, v in cfg['SECTION1'].items()}

如果需要列出所有部分,则应使用 cfg.sections()

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.