使用ConfigParser创建包含文件中指定的所有元素的类

时间:2012-09-27 11:43:13

标签: python python-2.7 configparser

我创建了一个类似.ini的文件,其中包含我稍后在程序中需要的所有值,请参阅下文:

[debugging]
checkForAbort = 10
...

[official]
checkForAbort = 30
...

我想将所有这些项目读入一个类,并使其可以从我的python项目的其他部分访问。 到目前为止我的代码如下:

from ConfigParser import SafeConfigParser
import glob

class ConfigurationParameters
    def __init__(self):
        self.checkForAbortDuringIdleTime = None     

    parser = SafeConfigParser()

    # making a list here in case we have multiple files in the future!
    candidatesConfiguration = ['my.cfg']
    foundCandidates = parser.read(candidatesConfiguration)
    missingCandidates = set(candidatesConfiguration) - set(found)
    if foundCandidates:
        print 'Found config files:', sorted(found)
    else
        print 'Missing files     :', sorted(missing)
        print "aborting..."


    # check for mandatory sections below
    for candidateSections in ['official', 'debugging']:
        if not parser.has_section(candidateSections)
            print "the mandatory section", candidateSections " is missing"
            print "aborting..."

    for sectionName in ['official', 'debugging']:
        for name, value in parser.items(section_name):
            self.name = value

我是python的新手,但我的代码仍然可以看到很多问题:

  • 我被迫为我的类文件中的每个项添加一个属性。并始终保持配置文件和我的班级同步。
  • 这个类不是单例,因此读取/解析将从导入的任何地方完成!
  • 如果在我的课程中没有定义配置文件的值,它可能会崩溃!

我该如何解决这个问题呢?可以动态创建类属性吗?

我的类只需要读取值,因此不需要写入配置文件!

3 个答案:

答案 0 :(得分:10)

What J.F. Sebastian said.

另外,你可以like Alex Martelli does in his Bunch class

档案MyConfig.py

from ConfigParser import SafeConfigParser


section_names = 'official', 'debugging'


class MyConfiguration(object):

    def __init__(self, *file_names):
        parser = SafeConfigParser()
        parser.optionxform = str  # make option names case sensitive
        found = parser.read(file_names)
        if not found:
            raise ValueError('No config file found!')
        for name in section_names:
            self.__dict__.update(parser.items(name))  # <-- here the magic happens


config = MyConfiguration('my.cfg', 'other.cfg')

档案foo.py

from MyConfig import config
# ...

档案MyProgram.py

from MyConfig import config

print config.checkForAbort

import foo

assert config is foo.config

Python Language Reference表示“导入语句分两步执行:(1)找到一个模块,并在必要时初始化它;(2)在本地命名空间中定义一个或多个名称(导入语句发生的范围)。“

这意味着,当一个模块被导入时,一个或多个本地名称被绑定到一个模块对象,并且只有在Python程序运行期间第一次导入它时才会被初始化(即从文件中读取)并运行)。

在上面的代码中,名称config只是一个引用模块对象属性的本地名称。在from MyConfig import config中引用(通过MyProgram)时,Python解释器已初始化模块对象。当MyProgram导入foo时,它已经初始化并绑定到模块fooMyProgram中的本地名称,我们可以将其称为foo.config。但这两个名称都指的是相同的对象。

答案 1 :(得分:2)

self.name = value无法正常工作。您可能意味着setattr(self, name, value)它动态地创建实例属性。

要使其成为单例,您可以将实例作为config / settings模块中的全局变量。在程序启动时初始化一次,例如logging模块为根记录器执行它:logging.config.fileConfig('logging.conf')

通常希望对属于dict的dict使用属性访问,例如带有命令行选项的argparse.Namespace

您可以稍后导入配置:from mypackage.config import config,例如mypackage/config.py

class Config(object):
    ...

config = Config() # empty or default config without any configuration

mypackage/__main__.py

from .config import config
...
# initialization code
config.update_from_file('mypackage.conf') # it might call `setattr()` inside

注意:即使您设置了属性,setattr()也能正常工作。在这种情况下,__dict__.update()会中断:

class XValidatorMixin(object):
    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        if value < 0:
            raise ValueError
        self._x = value


class CUpdate(XValidatorMixin):
    def __init__(self, **options):
        self.__dict__.update(options)


class CSetAttr(XValidatorMixin):
    def __init__(self, **options):
        for name, value in options.items():
            setattr(self, name, value)

for C in [CUpdate, CSetAttr]:
    o = C(a=1, b=2) # non-property attributes work as expected
    assert o.a == 1 and o.b == 2

o = CSetAttr(x=1)
assert o.x == 1 # setattr also sets property

o = CUpdate(x=1)
try:
    o.x # .update() doesn't set property
except AttributeError:
    pass
else:
    assert 0


try:
    o = CSetAttr(x=-1)  # invokes property setter
except ValueError: # that correctly reject negative values
    pass
else:
    assert 0

答案 2 :(得分:0)

pillmuncher的答案非常有用,可以很容易地在现有课程中使用。此外,还可以使用localconfig模块(link)自动转换数据类型。要获得这些附加功能,您可以使用以下内容:

from localconfig import LocalConfig

configfile = 'config.ini'
config = LocalConfig(configfile)
sections = list(config)

for section in sections:
    items = list(config.items(section))
    CLASS.__dict__.update(items)