我正在使用YAML配置文件。下面是在Python中加载配置的代码:
import os
import yaml
with open('./config.yml') as file:
config = yaml.safe_load(file)
字符串
这段代码实际上创建了一个字典。现在的问题是,为了访问值,我需要使用大量的括号。
YAML:
mysql:
user:
pass: secret
型
Python皮:
import os
import yaml
with open('./config.yml') as file:
config = yaml.safe_load(file)
print(config['mysql']['user']['pass']) # <--
型
我更喜欢这样的东西(点符号):
config('mysql.user.pass')
型
所以,我的想法是利用PyStache render()接口。
import os
import yaml
with open('./config.yml') as file:
config = yaml.safe_load(file)
import pystache
def get_config_value( yml_path, config ):
return pystache.render('{{' + yml_path + '}}', config)
get_config_value('mysql.user.pass', config)
型
这是一个“好”的解决方案吗?如果没有,还有什么更好的选择?
附加问题[已解决]
我决定用Ilja Everilä的溶液但现在我还有一个问题如何围绕DotConf创建 Package 器Config类?
下面的代码不起作用,但我希望你能明白我在做什么:
class Config( DotDict ):
def __init__( self ):
with open('./config.yml') as file:
DotDict.__init__(yaml.safe_load(file))
config = Config()
print(config.django.admin.user)
型
错误代码:
AttributeError: 'super' object has no attribute '__getattr__'
型
解决方案
你只需要把self
传递给超类的构造函数。
DotDict.__init__(self, yaml.safe_load(file))
型
更好的解决方案(Ilja Everilä)
super().__init__(yaml.safe_load(file))
型
7条答案
按热度按时间vhipe2zx1#
The Simple
您可以使用
reduce
从配置中提取值:字符串
如果您的YAML使用的语言子集非常有限,则此解决方案易于维护,并且具有很少的新边缘情况。
正确
使用适当的YAML解析器和工具,例如this answer。
卷积
简单地说(不要太认真),您可以创建一个允许使用属性访问的 Package 器:
型
请注意,对于关键字,如“as”,“pass”,“if”等,这将失败。
最后,你可能会变得非常疯狂(阅读:可能不是一个好主意),并定制
dict
来处理点字符串和元组键作为特殊情况,并对混合中抛出的项进行属性访问(及其限制):型
0kjbasz62#
一方面,您的示例采用了正确的方法,使用
get_config_value('mysql.user.pass', config)
而不是使用属性解决点式访问。我不确定你是否意识到你不是故意要做更直观的事情:字符串
即使重载了
__getattr__
,也不能让它工作,因为pass
是一个Python语言元素。但是,您的示例只描述了YAML文件的一个非常有限的子集,因为它不涉及任何序列集合,也不涉及任何复杂的键。
如果你想覆盖更多的小子集,你可以例如。扩展
ruamel.yaml
强大的往返对象:¹型
设置完成后,您可以运行以下命令:
型
给出:
型
这表明,只需多一点预先考虑和很少的额外工作,您就可以灵活地点访问许多到广泛的YAML文件,而不仅仅是那些由字符串标量作为键的递归Map组成的文件。
1.如图所示,您可以直接调用
config.string_access(
mysql.user.pass)
,而不用定义和使用get_config_value()
1.这将字符串和整数用作Map键,但是可以容易地扩展以支持其他键类型(布尔、日期、日期-时间)。
¹这是使用ruamel.yaml一个YAML 1.2解析器完成的,我是它的作者。
gstyhher3#
最后我使用了python-box。这个包提供了多种方式来读取配置文件(yaml,csv,json,...)。不仅如此,它还允许您直接传递
dict
或字符串:字符串
在Wiki中有更多的例子。
yqlxgs2m4#
这是一个相当古老的问题,但我来到这里寻找答案,但寻找更简单的解决方案。最后,提出了自己的解决方案,使用
easydict
库;使用pip install easydict
安装字符串
现在,只需使用有效的
yaml filename
调用yaml_load
:型
uajslkp65#
不久前我遇到了同样的问题,并构建了这个getter:
字符串
getter以递归方式(通过使用
__lookup
)从self.config
中查找配置值。如果您在为您的案例调整此功能时遇到困难,请随时寻求进一步的帮助。ccrfmcuu6#
我通常遵循的最佳实践是将config**(任何类型,不仅仅是yaml)转换为内存中的对象。
通过这种方式,基于文本的配置被1个函数打开,文本被丢弃,提供了一个漂亮的对象来处理,而不是让每个函数处理配置的内部**。这样所有函数只知道一个内部对象接口。如果从配置文件中添加/重命名/删除任何新参数,唯一要更改的函数是加载器函数,该函数将配置加载到内存对象中。
下面是一个示例我做的加载FloydHub配置yaml文件到内存中的对象。我觉得这是一个非常好的设计模式。
首先定义一个配置代表类,如下所示:
字符串
然后将yaml加载到对象中以供进一步用途:
型
样品yaml
型
fdbelqdn7#
Meta/Facebook的
hydra
库在这里可能太复杂了。Meta/Facebook的hydra
库的基础是omegaconf
,它可能满足您的需求。它的战斗测试和准备去和存储一切在ConfDict
的,我猜这是哈希Map,因此轻量级和快速。字符串