我创建了一个类似.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的新手,但我的代码仍然可以看到很多问题:
我该如何解决这个问题呢?可以动态创建类属性吗?
我的类只需要读取值,因此不需要写入配置文件!
答案 0 :(得分:10)
另外,你可以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
时,它已经初始化并绑定到模块foo
和MyProgram
中的本地名称,我们可以将其称为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)