Search code examples
pythonpyyaml

Object created with pyyaml doesn't have some attributes


I want to create an object with PyYAML. Consider the following code:

import yaml

doc = """
- !!python/object:__main__.Person {name: abc}
"""

class Person(object):
    def __init__(self, name):
        self.name = name
        self.age = 26

data = yaml.load(doc)
p = data[0]
print(dir(p))

The output of the above code is:

[__class__,__delattr__,__dict__,__dir__,__doc__,__eq__,__format__,__ge__,__getattribute__,__gt__,__hash__,__init__,__le__,__lt__,__module__,__ne__,__new__,__reduce__,__reduce_ex__,__repr__,__setattr__,__sizeof__,__slotnames__,__str__,__subclasshook__,__weakref__,name]

As you can see, my object does not have 'age' attribute! Therefor calling

print(p.age)

would generate an error.

How can I fix this problem? I know that I can use

doc = """
- !!python/object:__main__.Person {name: abc, age: 26}
"""

but it doesn't make sense to me because a class might have hundreds of internal attributes. It would be impossible to create such an object like this.


Solution

  • I found the solution (thanks to @asherbar 's comment):

    import yaml
    
    doc = """
    - !Person {name: abc}
    """
    
    def yamlobj(tag):
        def wrapper(cls):
            def constructor(loader, node):
                fields = loader.construct_mapping(node)
                return cls(**fields)
            yaml.add_constructor(tag, constructor)
            return cls
        return wrapper
    
    @yamlobj('!Person')
    class Person(object):
        def __init__(self, name):
            self.name = name
            self.age = 26
    
    data = yaml.load(doc)
    p = data[0]
    print(dir(p))