Search code examples
pythonpython-dataclassesxmltodict

Issues with lists of dataclasses being overwritten


I have an xml file that I convert using xmltodict to an ordereddict. I've created dataclasses to contain certain portions of the xml file, with the some of the top level dataclasses having attributes of either sub objects, or sometimes a list of subobjects if they're repeated. For each dataclass I've added a @classmethod from_dict, which returns itself and the input is an odict. For each dataclass if there's a basic (int, str, etc) attribute (xml tag name) I just retrieve the value by doing the following: cls.tag = input_dict.get('tag'). These values are retrievable and correct, but with lists of dataclasses, I do something like:


@dataclass()
class ContainerClass:
    windows: List[Window]
    title: str
    ...

    @classmethod
    def from_dict(cls: 'ContainerClass', input_dict: OrderedDict) -> 'ContainerClass':
        instance = cls
        instance.title = input_dict.get('title', '')
        temp_list = []
        windows_list = input_dict.get('windows', []) *returns list of odict objects (Windows once parsed)*
        for i in range(0, len(windows_list)):
            temp_list.append(Windows.from_dict(windows_list[i]))
            print(f"Window name: '{temp_list[i].name}'")
            *The above print statement will print out the name of all windows (10 windows)*

        instance.windows = temp_list

        for window in instance.windows:
            print(f"Window name: '{window.name}'")
            *The above print statement will print out the name of the last window 10 times*

        return instance

So I'm running into an issue where when I'm getting the windows from the Window dataclass from_dict, have the correct name. But then after assigning the list to cls The final window is just repeated for the total count of windows.

I've tried saving the list attribute as a generic list, and also a typing List of Windows. Windows is just an example here since there are many levels of nested dataclasses.


Solution

  • You aren't creating an instance of your class for the class method to return. You want something like

    @dataclass()
    class ContainerClass:
        windows: List[Window]
        title: str
        ...
    
        @classmethod
        def from_dict(cls: 'ContainerClass', input_dict: OrderedDict) -> 'ContainerClass':
            title = input_dict.get('title', '')
            windows_list = [Windows.from_dict(w) for w in input_dict.get('windows', [])]
    
            return cls(title, windows_list)
    

    Make sure that Windows.from_dict is actually returning an instance of Windows as well.