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

2024-05-29 10:02:45 发布

您现在位置:Python中文网/ 问答频道 /正文

我已经创建了一个类似.in I的文件,其中包含稍后在程序中需要的所有值,请参见以下内容:

[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新手,但我仍然可以看到我的代码有很多问题:

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

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

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


Tags: 文件nameinselfparserfor配置文件section
3条回答

self.name = value并不像您所期望的那样工作。您的意思可能是setattr(self, name, value)它动态地创建实例属性。

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

通常希望对本质上是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

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声明“Import语句分两步执行:(1)找到一个模块,必要时对其进行初始化;(2)在本地命名空间(Import语句发生的作用域)中定义一个或多个名称。”

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

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

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)

相关问题 更多 >

    热门问题