首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在PyYAML中加载yaml锚定义

在PyYAML中加载yaml锚定义
EN

Stack Overflow用户
提问于 2016-05-24 12:18:25
回答 3查看 7.4K关注 0票数 10

我在用PyYAML。是否有一种方法可以定义YAML锚点,因为它不会成为yaml.load加载的数据结构的一部分(我可以从字典中删除"wifi_parm“,但寻找一种更聪明的方法)?

example.yaml

代码语言:javascript
复制
wifi_parm: &wifi_params
  ssid: 1
  key: 2
test1:
  name: connectivity
  <<: *wifi_params
test2:
  name: connectivity_5ghz
  <<: *wifi_params

load_example.py

代码语言:javascript
复制
import yaml
import pprint

with open('aaa.yaml', 'r') as f:
    result = yaml.load(f)
pprint.pprint(result)

指纹:

代码语言:javascript
复制
{'test1': {'key': 2, 'name': 'connectivity', 'ssid': 1},
 'test2': {'key': 2, 'name': 'connectivity_5ghz', 'ssid': 1},
 'wifi_parm': {'key': 2, 'ssid': 1}}

我需要:

代码语言:javascript
复制
{'test1': {'key': 2, 'name': 'connectivity', 'ssid': 1},
 'test2': {'key': 2, 'name': 'connectivity_5ghz', 'ssid': 1}}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-05-24 14:11:53

在从PyYAML获得结果之前,将丢弃yaml.load()中的锚信息。这是根据YAML 1.1规范PyYAML遵循的(.锚名称是序列化的详细信息,一旦完成组合,将被丢弃)。这一点在YAML 1.2规范中没有改变(从2009年起)。在PyYAML中,您不能通过遍历result (递归)并测试哪些值可能是锚点来实现这一点,而不对解析器进行广泛的修改。

在我的ruamel.yaml (即YAML 1.2)中,在往返模式下,我为实际用于别名映射或序列的锚保留锚和别名(锚别名目前没有为标量保留,“未使用的”锚):

代码语言:javascript
复制
import ruamel.yaml

yaml = ruamel.yaml.YAML()

with open('aaa.yaml') as f:
    result = yaml.load(f)

yaml.dump(result, sys.stdout)

给予:

代码语言:javascript
复制
wifi_parm: &wifi_params
  ssid: 1
  key: 2
test1:
  <<: *wifi_params
  name: connectivity
test2:
  <<: *wifi_params
  name: connectivity_5ghz

实际上,您可以遍历映射(或者递归地遍历树),找到锚节点并删除它,而不知道键名。

代码语言:javascript
复制
import ruamel.yaml
from ruamel.yaml.comments import merge_attrib

yaml = ruamel.yaml.YAML()
with open('aaa.yaml') as f:
    result = yaml.load(f)

keys_to_delete = []
for k in result:
    v = result[k]
    if v.yaml_anchor():
        keys_to_delete.append(k)
    for merge_data in v.merge:  # update the dict with the merge data 
        v.update(merge_data[1])
        delattr(v, merge_attrib)
for k in keys_to_delete:
    del result[k]

yaml.dump(result, sys.stdout)

给予:

代码语言:javascript
复制
test1:
  name: connectivity
  ssid: 1
  key: 2
test2:
  name: connectivity_5ghz
  ssid: 1
  key: 2

一般地和递归地这样做也是可能的(例如,对于树中任何位置的锚和别名)。更新将像上面一样简单,但是您需要跟踪如何删除键,这不一定是映射值,它可以是序列项或标量。

票数 6
EN

Stack Overflow用户

发布于 2022-04-19 18:52:39

我今天也想这样做,我没有像@Anthon建议的那样切换到ruamel.yaml,而是找到了吡啶-保持锚存储库,这允许我继续使用pyyaml。这是那个回购的例子,它为我打开了盒子。

代码语言:javascript
复制
import yaml
from yaml_keep_anchors.yaml_anchor_parser import AliasResolverYamlLoader

with open('example/example.yaml', 'r') as fh:
    data = yaml.load(fh, Loader=AliasResolverYamlLoader)

assert data['key_three'].anchor_name == 'anchor'
assert data['key_two']['sub_key'].anchor_name == 'anchor_val'

更新的示例向ruamel.yaml的作者展示,标量确实可以被检查,以确定它们是否是别名。

Yaml档案:

代码语言:javascript
复制
  wifi_parm: &wifi_params
    ssid: 1
    key: &key some_key_here
  test1:
    name: connectivity
    key: *key
  test2:
    name: connectivity_5ghz
    key: *key

Python代码:

代码语言:javascript
复制
import yaml
from yaml_keep_anchors.yaml_anchor_parser import AliasResolverYamlLoader

with open('test.yaml', 'r') as f:
    result = yaml.load(f, Loader = AliasResolverYamlLoader)
print(result["test1"]["key"].__dict__)

这个指纹

代码语言:javascript
复制
{'_wrapped': 'some_key_here', '_anchor': 'key'}

因为引用的key是别名。

票数 1
EN

Stack Overflow用户

发布于 2022-09-17 03:47:37

这种方法支持任意数量的锚。如果省略了锚部分,则不会导致错误。

example.yaml:

代码语言:javascript
复制
__anchors__:
  wifi_parm: &wifi_params
    ssid: 1
    key: 2
test1:
  name: connectivity
  <<: *wifi_params
test2:
  name: connectivity_5ghz
  <<: *wifi_params

load_example.py:

代码语言:javascript
复制
import yaml
import pprint

with open('example.yaml', 'r') as f:
    result = yaml.safe_load(f)
result.pop('__anchors__', None)
pprint.pprint(result)

指纹:

代码语言:javascript
复制
{'test1': {'key': 2, 'name': 'connectivity', 'ssid': 1},
 'test2': {'key': 2, 'name': 'connectivity_5ghz', 'ssid': 1}}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37413345

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档