我试着做一本字典(从yaml数据中读取),表现得像一个类。因此,如果我调用class.key
,我将检索他的值。代码如下:
import errno
import sys
import yaml
backup_conf="""
loglevel: INFO
username: root
password: globalsecret
destdir: /dsk/bckdir/
avoidprojects:
matchregex: /bkp/
depots:
server1:
password: asecret
server2:
username: root
server3:
server4:
destdir: /disk2/bkp/
projects:
proj1:
matchregex:
- /backups/
- /bkp/
"""
class Struct:
def __init__(self, **entries):
self.__dict__.update(entries)
class Config:
def __init__(self, filename="backup.cfg", data=None):
self.cfg = {}
if data is None:
try:
fd = open(filename,'r')
try:
yamlcfg = yaml.safe_load(fd)
except yaml.YAMLError as e:
sys.exit(e.errno)
finally:
fd.close()
except ( IOError, OSError ) as e:
sys.exit(e.errno)
else:
try:
yamlcfg = yaml.safe_load(data)
except yaml.YAMLError as e:
sys.exit(e.errno)
self.cfg = Struct(**yamlcfg)
def __getattribute__(self, name):
try:
return object.__getattribute__(self, name)
except AttributeError:
return self.cfg.__getattribute__(name)
def get_depot_param(self,depot,param):
try:
self.depot_param = self.cfg.depots[depot][param]
except ( TypeError, KeyError) as e:
try:
self.depot_param = getattr(self.cfg, param)
except KeyError as e:
sys.exit(e.errno)
return self.depot_param
def get_project_param(self,project,param):
try:
self.project_param = self.cfg.projects[project][param]
except ( TypeError, KeyError) as e:
try:
self.project_param = getattr(self.cfg, param)
except KeyError as e:
sys.exit(e.errno)
return self.project_param
def get_project_matches(self,project):
try:
self.reglist = self.cfg.projects[project]['matchregex']
except KeyError as e:
try:
self.reglist = self.cfg.matchregex
except KeyError as e:
print "Error in configuration file: {0}: No default regex defined. Please add a matchregex entry on conf file".format(e)
sys.exit(e.errno)
if isinstance(self.reglist, str):
self.reglist = self.reglist.split()
return self.reglist
def get_depots(self):
return self.cfg.depots.keys()
if __name__ == '__main__':
# Read config file to cfg
config = Config(data=backup_conf)
代码运行良好,我能够像预期那样获取返回INFO
的数据。但是我想知道如何调用config.loglevel
,删除从我的self.cfg
实例变量中清晰地捕捉的cfg
。(当然,欢迎提供任何增强代码的提示)。在
只需将easydict与anyconfig结合使用。在
好吧,最简单的解决方案是使用PYYaml构造函数,即将类映射到yaml类型。在
① 使用构造函数
您所要做的就是使您的类成为
yaml.YAMLObject
的子类,添加yaml_tag
成员,告诉yaml何时使用该类构造该类的实例(而不是dict),然后设置:如您所见,我使用工厂方法来加载数据,并创建实例,
load
类方法就是为了这个目的。在这种方法的优点之一是,通过在yaml数据中写入type标记,可以直接键入所有元素。因此,如果您愿意,也可以使用类似的方法键入服务器,使您的yaml类似于:
^{pr2}$项目内每个项目的关键点都是相同的。在
② 使用
namedtuple
s如果不想更改yaml,那么可以使
Config
类成为namedtuple
的子类,当加载yaml数据时,可以从dict中创建namedtuple
为此,在下面的代码片段中,我将创建一个递归函数(嵌套在load类方法中),该函数遍历所有
dict
(和嵌套的dict
)并将它们转换为namedtuple
s当你运行它时:
③ 使用自定义的
yaml.Loader
来构建namedtuple
s我试着想出一种方法来解决这个问题,但经过一番尝试和错误之后,我明白这需要花费太多的时间来解决,而且它会变得过于复杂,无法作为一个简单易懂的解决方案可行。 只是为了好玩,下面是让它难以实现的原因。在
有一种方法可以创建自己的默认加载程序,并更改默认节点的转换方式。在默认加载程序中,可以重写创建
dict
s的方法,使其创建namedtuple
s:{{8}问题是只更新^树的值:
所以,正如我所说的,当然有办法,但是如果我花了太多时间去弄清楚,那就没有必要告诉你怎么做,因为这会让你(和未来的读者)很难理解。 正如我看到的@user1340544's answer,您可能需要考虑使用^{} 而不是{}(如果您没事的话)
外部包装)。在
结论
因此,正如您在这里看到的,
data
字段被构建为一个空dict,dict
在向调用方添加值之前,dict
被发送给调用者。因此,只有在dict构建完成后才添加这些值。 但是namedtuple
需要在一个单独的步骤中构建(即:在动手之前,您需要知道所有的键),因此无法使用这种方法。在我个人更倾向于选择①,使用标记,因为您可以使用它映射到的类来验证配置(并在配置项丢失、输入错误或额外项时发出警报)。 您还可以从为每种类型使用不同的名称中获益,这样在解析配置文件时就可以很容易地报告出了什么问题,而所有这些都需要最少的额外代码。当然,选择②做得很好。在
高温
在将不同的映射键指定为属性后,您可以执行以下操作,但代价是无法轻松迭代不同的映射键:
获得:
^{pr2}$另一个解决方案是使
__getattr__()
更加智能:这会给你和以前一样的输出。在
相关问题 更多 >
编程相关推荐