3

我正在寻找一种解决方案,允许我使用配置文件数据的属性。

我希望能够做这样的事情:

config = Config('config.ini')
print config.section1.user
print config.section2.password

我知道 ConfigParser 可以让我做类似的事情config['section1']['user'],但这太丑陋了,我们不能做得更好吗?

该解决方案必须适用于 Python 2.5 或更高版本。

4

4 回答 4

2

它并不难看,它更好 - 点表示法意味着在另一个自定义类的对象中可能有一些自定义类的对象。更可行的方法是使用字典(使用括号表示法)。

但如果你坚持,你可能可以这样翻译代码:

def config2object(config):
    """
    Convert dictionary into instance allowing access to dictionary keys using
    dot notation (attributes).
    """
    class ConfigObject(dict):
        """
        Represents configuration options' group, works like a dict
        """
        def __init__(self, *args, **kwargs):
            dict.__init__(self, *args, **kwargs)
        def __getattr__(self, name):
            return self[name]
        def __setattr__(self, name, val):
            self[name] = val
    if isinstance(config, dict):
        result = ConfigObject()
        for key in config:
            result[key] = config2object(config[key])
        return result
    else:
        return config

测试显示了预期的结果:

>>> c1 = {
    'conf1': {
        'key1': 'aaa',
        'key2': 12321,
        'key3': False,
        },
    'conf2': 'bbbb',
    }
>>> c1
{'conf2': 'bbbb', 'conf1': {'key3': False, 'key2': 12321, 'key1': 'aaa'}}
>>> c2 = config2object(c1)
>>> c2.conf1
{'key3': False, 'key2': 12321, 'key1': 'aaa'}
>>> c2.conf1.key1
'aaa'
>>> c2.conf1.key3
False
>>> c2.conf2
'bbbb'

编辑:Sven Marnach 指出这Config('config.ini')是一些自定义类实例。它不是字典,它有一些自定义方法可能非常有用,但可能会使某些配置选项无法访问(当存在名称冲突时)。因此,首选方法不是使用我提到的解决方案,而是使用括号表示法来访问配置选项。

于 2012-03-19T16:42:14.210 回答
1

我也想使用点符号来访问 ConfigParser 从配置文件中读取的属性。(在 github 上可用)。

这是我扩展 ConfigParser 的尝试:

from ConfigParser import ConfigParser as BaseClass

SPACE = " "
UNDERSCORE = "_"


def internal_name(name, needle=SPACE, replacement=UNDERSCORE):
    return name.replace(needle, replacement)


def reverse_name_internalization(name):
    return internal_name(name, needle=UNDERSCORE, replacement=SPACE)


class DotNotationConfigParser(BaseClass, object):

    def __init__(self, coersion_map=None, *args, **kwargs):
        super(DotNotationConfigParser, self).__init__(*args, **kwargs)

        self.optionxform = internal_name
        self.section_attr = None

    def get_internalized_section(self, section):
        if self.has_section(section):
            return internal_name(section)

    def __set_section_obj(self, internalized_section):
        if self.has_section(internalized_section):
            section = internalized_section
        else:
            section = reverse_name_internalization(internalized_section)

        if self.get_internalized_section(section):
            # set an attr to an object instance with section items
            obj = type('', (), dict(self.items(section)))()
            setattr(self, internalized_section, obj)

    def __getattr__(self, attr):
        try:
            return super(DotNotationConfigParser, self).__getattribute__(attr)
        except AttributeError:
            section = attr
            self.__set_section_obj(section)
            return super(DotNotationConfigParser, self).__getattribute__(attr)


try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO
configuration_file = """
[section 1]
foo = the foo value
bar = the bar value
[section 2]
index = 3
repeat = False
[section_n]
string = This is some text.
ip = 10.0.1.1
"""
configuration_file = StringIO(configuration_file)

parser = DotNotationConfigParser()
parser.readfp(configuration_file)

assert parser.section_1.foo == 'the foo value'
assert parser.section_1.bar == 'the bar value'
assert type(parser.section_2.index) is not int
for section_name in ('section_1', 'section_2', 'section_n'):
    section = getattr(parser, section_name)
    options = [option for option in dir(section)
               if not option.startswith('__')]
    for option in options:
        print section_name, ": ", getattr(section, option)

print "dot notation", parser.section_1.foo
于 2015-05-23T23:43:04.603 回答
0

我已经设法以非常简洁的方式获得了你需要的东西。使用点符号总是更好,我也希望在我的项目中使用它。假设在您的项目根目录中,您有里面的Setup目录setup.cfg。您还将项目根路径添加到 env 变量中(为了便于阅读此代码)

import os
import configparser


class Section:
    def __init__(self):
        pass


class Setup:
    def __init__(self):
        self.setup_dict = self.load_setup()
        self.fill_setup()

    def load_setup(self):
        setup = configparser.RawConfigParser()
        setup.read(os.environ.get('PROJECT_ROOT_PATH') + "/Setup/setup.cfg")
        return {section: item_dict for (section, item_dict) in zip(list(setup), [dict(section) for section in dict(setup).values()])}

    @staticmethod
    def add_section(data):
        section = Section()
        vars(section).update(data)
        return section

    def fill_setup(self):
        for name in self.setup_dict.keys():
            vars(self).update({name.lower(): self.add_section(self.setup_dict[name])})

问题是,对于读取配置文件时的点表示法,您需要一个类,其中包含表示 cfg 文件部分的类(上面的部分类),而这些类又具有 cfg 部分值的键值对作为实例变量.

然后您可以从文件中导入设置(或您将调用您的类的任何名称)并像这样使用:

from load_setup import Setup

setup = Setup()
value = setup.section.item
于 2021-10-26T13:46:07.663 回答
0

我写了一个简单的包configdothttps ://github.com/jjnurminen/configdot 。它允许通过语法config.section.item(读取和写入)访问配置项。作为奖励,它还允许您直接在 INI 文件中使用(有限数量的)Python 数据类型。

于 2020-11-18T15:26:04.520 回答