我正在努力与PyYAML文档理解一个可能很容易的事情。 我有一个将字符串名称映射到python对象的字典:
lut = { 'bar_one': my_bar_one_obj,
'bar_two': my_bar_two_obj }
我想加载这样的YAML文件并将所有“foo”节点映射到我的字典对象(反向,转储,不是真的有必要)
node1:
# ...
foo: "bar_one"
node2:
# ...
foo: "bar_two"
我的第一个想法是使用add_constructor
,但我找不到给它额外的kwarg的方法。也许是自定义装载机?
PyYAML文档并没有真正帮助,或者我可能正在寻找错误的关键字......
我可以接受使用像
这样的自定义标签node1:
# ...
foo: !footag "bar_one"
node2:
# ...
foo: !footag "bar_two"
但仅检测foo
个节点会更好
答案 0 :(得分:2)
您不是在寻找错误的关键字,这不是我所知道的任何YAML解析器。 YAML解析器加载一个可能复杂的自包含数据结构。而你想要做的是在一个解析步骤中将自包含结构合并到一个已经存在的结构(lut
)中。构建解析器是为了通过提供替代例程来实现调整,而不是通过提供例程+数据
内置于PyYAML中没有选项,即没有内置的方法告诉加载器有关{Y}使PyYAML对它做什么的加载,当然也没有附加键值对(假设这就是你对节点的意义)作为其键的值。
获得所需内容的最简单方法可能是使用一些后期处理,其中包含lut
和从YAML文件(也是一个字典)加载的数据并将两者合并。
如果您想尝试使用lut
执行此操作,那么您需要做的是使用add_constructor
方法构建一个类,并使用__call__
创建一个类的实例参数,并将该实例作为替代构造函数传递):
lut
你可以用u'tag替换'your_tag':yaml.org,2002:map'如果你想要的话 你的构造函数来处理(所有)正常的dicts。
另一个选择是在YAML加载期间执行此操作,但是再一次,您不能只调整class ConstructorWithLut:
def __init__(self, lut):
self._lut = lut
def __call__(self):
# the actual constructor routine added by add_constructor
constructor_with_lut(lut)
SomeConstructor.add_constructor('your_tag', constructor_with_lut)
或其中一个组成部分(Loader
),因为您通常在课程中提交而不是宾语。您需要一个对象才能附加Constructor
。所以你要做的是创建你自己的构造函数和你自己的使用该构造函数的加载器,然后是一个实例化你的加载器的lut
替换,附加load()
(只需将其添加为唯一属性,或者将其作为参数传递并将其传递给构造函数。)
您的构造函数(应该是现有构造函数之一的子类)必须拥有自己的lut
,它首先调用父类“construct_mapping()
”,并在返回结果之前检查是否它可以更新已分配construct_mapping()
的属性。您无法根据查看lut
的dict键来执行此操作,因为如果您有这样的密钥,则无法访问需要分配给的父节点foo
。您需要做的是查看映射的任何值是否为具有键名lut
的dict,如果是,则可以使用字典根据关联的值更新foo
与lut
。
我肯定会首先使用两个例程来实现后期处理阶段:
foo
我不确定你对“分配所有foo节点”的真正含义是什么,YAML数据在顶层没有节点,它只有键和值。所以你要么分配那一对,要么只分配它的值(一个字典)。
一旦这两个例程工作得令人满意,您就可以尝试实施基于def update_from_yaml(your_dict, yaml_data):
for node_key in yaml_data:
node_value = yaml_data[node_key]
map_value(your_dict, node_key, node_value)
def map_value(your_dict, key, value):
foo_val = value.get('foo')
if foo_val is None: # key foo not found
return
your_dict[foo_val] = value # or = {key: value}
或add_constructor
的替代方案,在这些方案中,您应该能够至少重复使用Loader