How to Convert YAML to List of Objects in Python

In this tutorial, you’ll learn how to convert YAML data into a list of Python objects using various methods.

We’ll cover simple conversions using dictionaries, using custom classes, handling nested structures, and dealing with cyclic references.

 

 

Custom Class for Object Creation

To convert YAML data into instances of a custom class, you can define a class and use a custom constructor with PyYAML.

import yaml
class Person:
    def __init__(self, name, age, city):
        self.name = name
        self.age = age
        self.city = city
def person_constructor(loader, node):
    values = loader.construct_mapping(node)
    return Person(**values)

class CustomLoader(yaml.SafeLoader):
    pass

CustomLoader.add_constructor('!Person', person_constructor)
yaml_data = """
- !Person
  name: Omar
  age: 28
  city: Giza
- !Person
  name: Mona
  age: 32
  city: Luxor
"""
people = yaml.load(yaml_data, Loader=CustomLoader)
for person in people:
    print(f"{person.name} is {person.age} years old and lives in {person.city}")

Output:

Omar is 28 years old and lives in Giza
Mona is 32 years old and lives in Luxor

Each YAML item is loaded into a Person object, and you print out their details.

 

Custom Class for Nested Objects

For YAML data with nested structures, you can create nested classes and adjust the constructor to handle them.

import yaml
class Address:
    def __init__(self, city, street):
        self.city = city
        self.street = street

class Person:
    def __init__(self, name, age, address):
        self.name = name
        self.age = age
        self.address = address
def address_constructor(loader, node):
    values = loader.construct_mapping(node)
    return Address(**values)
def person_constructor(loader, node):
    values = loader.construct_mapping(node)
    return Person(**values)

class CustomLoader(yaml.SafeLoader):
    pass

CustomLoader.add_constructor('!Person', person_constructor)
CustomLoader.add_constructor('!Address', address_constructor)
yaml_data = """
- !Person
  name: Salma
  age: 27
  address: !Address
    city: Aswan
    street: Nile Avenue
"""
people = yaml.load(yaml_data, Loader=CustomLoader)
person = people[0]
print(f"{person.name} is {person.age} years old and lives on {person.address.street}, {person.address.city}")

Output:

Salma is 27 years old and lives on Nile Avenue, Aswan

The nested Address object is properly constructed and associated with the Person object.

 

Using YAMLObject

You can use yaml.YAMLObject to map YAML entries to Python objects without custom constructors.

import yaml
yaml_data = """
!Person
name: Karim
age: 35
city: Hurghada
"""
class Person(yaml.YAMLObject):
    yaml_tag = '!Person'
    def __init__(self, name, age, city):
        self.name = name
        self.age = age
        self.city = city
person = yaml.load(yaml_data, Loader=yaml.Loader)
print(f"{person.name} is {person.age} years old and lives in {person.city}")

Output:

Karim is 35 years old and lives in Hurghada

 

Handle Cyclic References

When dealing with YAML data that has cyclic references, you can enable the resolver in PyYAML to handle them.

import yaml
yaml_data = """
a: &id001
  name: Ali
  friend: *id001
"""
data = yaml.safe_load(yaml_data)
print(data['a']['friend']['name'])

Output:

Ali

The cyclic reference is resolved, and you can access the nested data without causing infinite recursion.

Leave a Reply

Your email address will not be published. Required fields are marked *