问题描述
我正在尝试在 python 中创建一个创建自定义 python 对象的 yaml 序列.对象需要用 __init__ 之后解构的字典和列表来构造.但是,construct_mapping 函数似乎并没有构建嵌入序列(列表)和字典的整个树.
考虑以下几点:
I am trying to make a yaml sequence in python that creates a custom python object. The object needs to be constructed with dicts and lists that are deconstructed after __init__. However, it seems that the construct_mapping function does not construct the entire tree of embedded sequences (lists) and dicts.
Consider the following:
import yaml class Foo(object): def __init__(self, s, l=None, d=None): self.s = s self.l = l self.d = d def foo_constructor(loader, node): values = loader.construct_mapping(node) s = values["s"] d = values["d"] l = values["l"] return Foo(s, d, l) yaml.add_constructor(u'!Foo', foo_constructor) f = yaml.load(''' --- !Foo s: 1 l: [1, 2] d: {try: this}''') print(f) # prints: 'Foo(1, {'try': 'this'}, [1, 2])'
这很好用,因为 f 包含对 l 和 d 对象的引用,这些对象实际上在 after<之后填充了数据/strong> Foo 对象已创建.
This works fine because f holds the references to the l and d objects, which are actually filled with data after the Foo object is created.
现在,让我们做一些更复杂的事情:
Now, let's do something a smidgen more complicated:
class Foo(object): def __init__(self, s, l=None, d=None): self.s = s # assume two-value list for l self.l1, self.l2 = l self.d = d
现在我们得到以下错误
Traceback (most recent call last): File "test.py", line 27, in <module> d: {try: this}''') File "/opt/homebrew/lib/python2.7/site-packages/yaml/__init__.py", line 71, in load return loader.get_single_data() File "/opt/homebrew/lib/python2.7/site-packages/yaml/constructor.py", line 39, in get_single_data return self.construct_document(node) File "/opt/homebrew/lib/python2.7/site-packages/yaml/constructor.py", line 43, in construct_document data = self.construct_object(node) File "/opt/homebrew/lib/python2.7/site-packages/yaml/constructor.py", line 88, in construct_object data = constructor(self, node) File "test.py", line 19, in foo_constructor return Foo(s, d, l) File "test.py", line 7, in __init__ self.l1, self.l2 = l ValueError: need more than 0 values to unpack
这是因为yaml构造函数是在嵌套before的外层开始,在所有节点完成之前构造对象.有没有办法颠倒顺序并首先从深度嵌入(例如嵌套)对象开始?或者,有没有办法让构造至少在节点的对象被加载之后发生?
This is because the yaml constructor is starting at the outer layer of nesting before and constructing the object before all nodes are finished. Is there a way to reverse the order and start with deeply embedded (e.g. nested) objects first? Alternatively, is there a way to get construction to happen at least after the node's objects have been loaded?
推荐答案
好吧,你知道什么.我找到的解决方案非常简单,但文档却没有那么完善.
Well, what do you know. The solution I found was so simple, yet not so well documented.
Loader 类文档清楚地表明 construct_mapping 方法只需要在单个参数(node)中.但是,在考虑编写自己的构造函数后,我查看了源代码,答案是 就在那里!该方法还接受一个参数deep(默认为False).
The Loader class documentation clearly shows the construct_mapping method only takes in a single parameter (node). However, after considering writing my own constructor, I checked out the source, and the answer was right there! The method also takes in a parameter deep (default False).
def construct_mapping(self, node, deep=False): #...
所以,正确使用的构造方法是
So, the correct constructor method to use is
def foo_constructor(loader, node): values = loader.construct_mapping(node, deep=True) #...
我猜 PyYaml 可以使用一些额外的文档,但我很感激它已经存在.
I guess PyYaml could use some additional documentation, but I'm grateful that it already exists.