Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Can';t从PyYAML调用的构造函数中的参数构造对象_Python_Python 3.x_Yaml_Pyyaml - Fatal编程技术网

Python Can';t从PyYAML调用的构造函数中的参数构造对象

Python Can';t从PyYAML调用的构造函数中的参数构造对象,python,python-3.x,yaml,pyyaml,Python,Python 3.x,Yaml,Pyyaml,我有一个YAML文件,如下所示: --- !Frog name: tree frog colour: green friends: - !Frog name: motorbike frog - !Frog name: blue arrow frog 以及一个python程序,该程序使用PyYAML根据文件创建对象: import yaml class Frog(): def __init_

我有一个YAML文件,如下所示:

---
!Frog
    name: tree frog
    colour: green
    friends:
        - !Frog
          name: motorbike frog
        - !Frog
          name: blue arrow frog
以及一个python程序,该程序使用PyYAML根据文件创建对象:

import yaml

class Frog():
    def __init__(self, name, colour="", friends=None):
        self.name = name
        self.colour = colour
        self.friends = {}
        if friends != None:
            for f in friends:
                self.friends[f.name] = f
        print("{}'s friends: {}".format(self.name, self.friends))

# Constructor for YAML
def frogConstructor(loader, node) :
    fields = loader.construct_mapping(node)
    return Frog(**fields)

yaml.add_constructor('!Frog', frogConstructor)

f = open("frog.yaml")
loaded = yaml.load(f)
正如您在上面的代码中所看到的,我正在尝试从
friends
参数(其中键是青蛙的名字,值是实际的青蛙对象)到
\uuu init\uuu
方法创建一个
self.friends
字典。但是,上面的代码会产生以下输出:

tree frog's friends: {}
motorbike frog's friends: {}
blue arrow frog's friends: {}

正如您所看到的,
self.friends
字典对于所有三只青蛙都是空的,但是树蛙应该有两个朋友。若我只是简单地交了
self.friends=friends
,它会像预期的那个样工作:
self.friends
是一个朋友青蛙的列表。我做错了什么?

如果你做了
self.friends=friends
,事情就会发生,这并不奇怪。您将一个最初为空的列表分配给
self.friends
,该列表稍后将由YAML解析器附加到该列表中

如果希望在构建
Frog()
之前填充该列表,则必须为
construct\u mapping()
提供
deep=True
参数,这样做将确保首先创建底层非标量构造以及标量构造

def frogConstructor(loader, node):
    fields = loader.construct_mapping(node, deep=True)
    return Frog(**fields)
但是,您的代码还存在一些问题(但没有一个问题禁止上述功能):

  • 只有一个
    None
    ,因此如果朋友不是None,则使用
    比使用
    如果朋友!=无:
  • yaml.load
    是不安全的,因此如果您无法完全控制输入,则可能意味着光盘被擦除(或更糟)。PyYAML没有为此警告您(在我的解析器中,您必须显式地提供不安全的
    加载程序
    ,以防止出现警告消息)
  • 如果代码>树蛙< /代码>是自恋的,足以认为自己是一个朋友,或者如果它的一个朋友认为“代码>树蛙< /代码>一个朋友,你可能想要使用一个锚和别名来指示这样(并且不仅仅是在不同的<代码>青蛙< /代码>上使用同一个名字),这对于您正在使用的简单构造函数是不起作用的
  • frogConstructor
    作为一个函数名,不应使用驼峰大小写,而应使用
    frog\u构造函数
由于上述原因,我不会使用
deep=True
参数,而是通过使用两阶段构造函数来寻求更安全、更完整的解决方案:

from ruamel import yaml

class Frog():
    def __init__(self, name):
        self.name = name

    def set_values(self, colour="", friends=None):
        self.colour = colour
        self.friends = {}
        if friends is not None:
            for f in friends:
                self.friends[f.name] = f
        print("{}'s friends: {}".format(self.name, self.friends))

    def __repr__(self):
        return "Frog({})".format(self.name)

# Constructor for YAML
def frog_constructor(loader, node):
    fields = loader.construct_mapping(node)
    frog = Frog(fields.pop('name'))
    yield frog
    frog.set_values(**fields)

yaml.add_constructor('!Frog', frog_constructor, yaml.SafeLoader)

f = open("frog.yaml")
loaded = yaml.safe_load(f)
这样您就可以解析这个
frog.yaml

!Frog &tree_frog
    name: tree frog
    colour: green
    friends:
        - !Frog
          name: motorbike frog
          friends:
            - *tree_frog
        - !Frog
          name: blue arrow frog
要获取输出,请执行以下操作:

tree frog's friends: {'blue arrow frog': Frog(blue arrow frog), 'motorbike frog': Frog(motorbike frog)}
motorbike frog's friends: {'tree frog': Frog(tree frog)}
blue arrow frog's friends: {}