Search code examples
pythonrecursionpython-dataclasses

Recursively changing values of a nested dataclass in python


I have a dataclass like this:

class chapter:
    title: str
    text: str = ''
    chapter: List['chapter'] = field(default_factory=list)
    removed: bool = False
    

Say there is a list object that contains instances of that dataclass with these values:

content = [
    chapter(
        'chapter 1',
        chapter=[
            chapter('subchapter 1', "Lorem ipsum dolor"),
            chapter('subchapter 2', "Nullam a ligula")
        ]
    ),
    chapter(
        'chapter 2',
        chapter=[
            chapter('subchapter 1', "Fusce eget commodo augue"),
            chapter('subchapter 2', "Pellentesque pretium")
        ]
    ),
    chapter(
        'chapter 3', removed=True
    ),
    chapter(
        'chapter 3',
        chapter=[
            chapter('subchapter 1', "Duis sit amet tempus lectus"),
        ]
    ),
]

Let's say I want to recursively set values removed to True for a selected chapter with an index 0, and in all subchapters of the chapter. How can I do that? Any suggestions are appreciated.


Solution

  • The naming in your code is a bit confusing - you should name the class Chapter instead of chapter and the list chapter should probably be called chapters.

    Having said that, this appears to be what you want:

    from typing import List
    from dataclasses import dataclass, field
    
    
    @dataclass
    class Chapter:
        title: str
        text: str = ''
        chapters: List['Chapter'] = field(default_factory=list)
        removed: bool = False
    
        def remove(self):
            self.removed = True
            for chapter in self.chapters:
                chapter.remove()
    
    
    content = [
        Chapter(
            title='chapter 1',
            chapters=[
                Chapter('subchapter 1', "Lorem ipsum dolor"),
                Chapter('subchapter 2', "Nullam a ligula")
            ]
        ),
        Chapter(
            'chapter 2',
            chapters=[
                Chapter('subchapter 1', "Fusce eget commodo augue"),
                Chapter('subchapter 2', "Pellentesque pretium")
            ]
        ),
        Chapter(
            'chapter 3', removed=True
        ),
        Chapter(
            'chapter 3',
            chapters=[
                Chapter('subchapter 1', "Duis sit amet tempus lectus"),
            ]
        ),
    ]
    
    
    content[0].remove()
    print(content)
    

    Calling .remove() on a chapter sets .removed to True, but also calls .remove() on any of its subchapters, recursively setting .removed on all of them and their subchapters.