Search code examples
pythontagsyamlpyyaml

Default constructor parameters in pyyaml


I haven't been able to find out how to do this in the PyYAML documentation. I want to represent python classes I've defined in YAML, and have a default value given to a parameter in the constructor if it's not specified in the YAML. For example:

>>> class Test(yaml.YAMLObject):
...     yaml_tag = u"!Test"
...     def __init__(self, foo, bar=3):
...             self.foo = foo
...             self.bar = bar
...     def __repr__(self):
...             return "%s(foo=%r, bar=%r)" % (self.__class__.__name__, self.foo, self.bar)
... 
>>> yaml.load("""
... --- !Test
... foo: 5
... """)
Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
  File "<stdin>", line 7, in __repr__
AttributeError: 'Test' object has no attribute 'bar'

I expected that it would create a Test object with bar=3, but I guess it bypasses my constructor when it creates the object. If I include a mapping for bar in the YAML, everything works as expected:

>>> yaml.load("""
... --- !Test
... foo: 5
... bar: 42
... """)
Test(foo=5, bar=42)

Does anyone know how I can have it use a default value?


Solution

  • I encountered the same problem: yaml_tag doesn't work for some reason. So I used alternative approach:

    import yaml
    
    def constructor(loader, node) :
        fields = loader.construct_mapping(node)
        return Test(**fields)
    
    yaml.add_constructor('!Test', constructor)
    
    class Test(object) :
        def __init__(self, foo, bar=3) :
            self.foo = foo
            self.bar = bar
        def __repr__(self):
            return "%s(foo=%r, bar=%r)" % (self.__class__.__name__, self.foo, self.bar)
    
    print yaml.load("""
    - !Test { foo: 1 }
    - !Test { foo: 10, bar: 20 }""")
    

    Output:

    [Test(foo=1, bar=3), Test(foo=10, bar=20)]