我正在寻找一个允许我使用配置文件数据属性的解决方案。
我希望能够做到这样的事情:
config = Config('config.ini')
print config.section1.user
print config.section2.password
我确实知道ConfigParser会允许我像config['section1']['user']
那样做,但那太难看了,我们不能做得更好吗?
解决方案必须使用Python 2.5或更高版本。
答案 0 :(得分: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')
是一些自定义类实例。它不是字典,它有一些非常有用的自定义方法,但可能使某些配置选项无法访问(当存在名称冲突时)。因此,首选方法不是使用我提到的解决方案,而是使用括号表示法来访问配置选项。
答案 1 :(得分:1)
我也想使用点符号来访问ConfigParser从配置文件中读取的属性。 (Available on 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
答案 2 :(得分:0)
我写了一个简单的程序包configdot
:https://github.com/jjnurminen/configdot。它允许使用语法config.section.item
(读和写)访问配置项。另外,它还允许您直接在INI文件中使用(数量有限)Python数据类型。