gpt4 book ai didi

Python:使用 "dot notation"访问 YAML 值

转载 作者:太空狗 更新时间:2023-10-29 19:35:46 25 4
gpt4 key购买 nike

我正在使用 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() 接口(interface)。

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 创建一个包装器 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 传递给父类(super class)的构造函数。

DotDict.__init__(self, yaml.safe_load(file))

更好的解决方案(Ilja Everilä)

super().__init__(yaml.safe_load(file))

最佳答案

简单

你可以使用 reduce从配置中提取值:

In [41]: config = {'asdf': {'asdf': {'qwer': 1}}}

In [42]: from functools import reduce
...:
...: def get_config_value(key, cfg):
...: return reduce(lambda c, k: c[k], key.split('.'), cfg)
...:

In [43]: get_config_value('asdf.asdf.qwer', config)
Out[43]: 1

如果您的 YAML 使用非常有限的语言子集,则此解决方案易于维护并且几乎没有新的边缘情况。

正确的

使用适当的 YAML 解析器和工具,例如 this answer .


错综复杂

简单来说(不要太认真),您可以创建一个允许使用属性访问的包装器:

In [47]: class DotConfig:
...:
...: def __init__(self, cfg):
...: self._cfg = cfg
...: def __getattr__(self, k):
...: v = self._cfg[k]
...: if isinstance(v, dict):
...: return DotConfig(v)
...: return v
...:

In [48]: DotConfig(config).asdf.asdf.qwer
Out[48]: 1

请注意,这对“as”、“pass”、“if”等关键字无效。

最后,您可能会变得非常疯狂(阅读:可能不是一个好主意)并自定义 dict 来处理点分字符串和元组键作为一种特殊情况,对混合中抛出的项目进行属性访问(有其局限性):

In [58]: class DotDict(dict):
...:
...: # update, __setitem__ etc. omitted, but required if
...: # one tries to set items using dot notation. Essentially
...: # this is a read-only view.
...:
...: def __getattr__(self, k):
...: try:
...: v = self[k]
...: except KeyError:
...: return super().__getattr__(k)
...: if isinstance(v, dict):
...: return DotDict(v)
...: return v
...:
...: def __getitem__(self, k):
...: if isinstance(k, str) and '.' in k:
...: k = k.split('.')
...: if isinstance(k, (list, tuple)):
...: return reduce(lambda d, kk: d[kk], k, self)
...: return super().__getitem__(k)
...:
...: def get(self, k, default=None):
...: if isinstance(k, str) and '.' in k:
...: try:
...: return self[k]
...: except KeyError:
...: return default
...: return super().get(k, default=default)
...:

In [59]: dotconf = DotDict(config)

In [60]: dotconf['asdf.asdf.qwer']
Out[60]: 1

In [61]: dotconf['asdf', 'asdf', 'qwer']
Out[61]: 1

In [62]: dotconf.asdf.asdf.qwer
Out[62]: 1

In [63]: dotconf.get('asdf.asdf.qwer')
Out[63]: 1

In [64]: dotconf.get('asdf.asdf.asdf')

In [65]: dotconf.get('asdf.asdf.asdf', 'Nope')
Out[65]: 'Nope'

关于Python:使用 "dot notation"访问 YAML 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39463936/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com