Python Forum
Recursively convert nested dicts to dict subclass
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Recursively convert nested dicts to dict subclass
#1
Star 
Context: Elegant solution needed to monitor and save database changes during runtime. To minimze IO, the solution should be based on signals rather than polling and comparing against file content.

Solution: Use a callback to start a save timer following database alteration. Thus, I subclassed a dict (Observer) and overridden __setitem__ method to handle the addition of new keys. As the dict content is loaded from a JSON, all nested dict object must also be converted after update() is called.

Edit: it works! can it be further improved?


#!/usr/bin/python3
from typing import Callable


class Observer(dict):
    def __init__(self, *args, callback: Callable):
        super().__init__(*args)
        self.cb = callback

    def __setitem__(self, item: any, value: any):
        """ Fires a callback function when a value is changed """
        value = Observer(value, callback=self.cb) if isinstance(value, dict) else value
        super().__setitem__(item, value)
        if isinstance(value, dict):
            self._convert(value)
        self.cb()

    def update(self, *args):
        """ Converts dict objects after update """
        super().update(*args)
        self._convert(self)

    def _convert(self, d: dict):
        """ Recursively converts nested dict to Observer subclass """
        for key, value in d.items():
            if isinstance(value, dict):
                d[key] = Observer(value, callback=self.cb)
                self._convert(value)


class Database(Observer):
    def __init__(self, d):
        super().__init__(self, callback=lambda: None)  # ##
        self.update(d)


def demo():
    db = Database({1: {"foo": ["bar"]}, 2: {3: {"bubu": 0}}})
    db[4] = {5: {6: {7: {}}}}

    print(f"{type(db)}\n")
    print("update")
    print(f"{type(db[1])=}")
    print(f"{type(db[2])=}")
    print(f"{type(db[2][3])=}")
    print("\nsetitem")
    print(f"{type(db[4])=}")
    print(f"{type(db[4][5])=}")
    print(f"{type(db[4][5][6])=}")
    print(f"{type(db[4][5][6][7])=}")
    print()
    print(db)


demo()
Output:

Quote:<class '__main__.Database'>

update
type(db[1])=<class '__main__.Observer'>
type(db[2])=<class '__main__.Observer'>
type(db[2][3])=<class '__main__.Observer'>

setitem
type(db[4])=<class '__main__.Observer'>
type(db[4][5])=<class '__main__.Observer'>
type(db[4][5][6])=<class '__main__.Observer'>
type(db[4][5][6][7])=<class '__main__.Observer'>

{1: {'foo': ['bar']}, 2: {3: {'bubu': 0}}, 4: {5: {6: {7: {}}}}}
Reply
#2
(Jan-22-2021, 04:34 AM)Alfalfa Wrote: As the dict content is loaded from a JSON, all nested dict object must also be converted after update() is called.
I think you can define custom JSONDecoder and set object_hook=Observer and override the default dict.
If you can't explain it to a six year old, you don't understand it yourself, Albert Einstein
How to Ask Questions The Smart Way: link and another link
Create MCV example
Debug small programs

Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Modifying a dictionary recursively SpongeB0B 2 119 Yesterday, 04:09 PM
Last Post: Gribouillis
  Convert nested sample json api data into csv in python shantanu97 3 2,932 May-21-2022, 01:30 PM
Last Post: deanhystad
  How to return the next page from json recursively? sandson 0 1,198 Apr-01-2022, 11:01 PM
Last Post: sandson
  Convert python dataframe to nested json kat417 1 6,419 Mar-18-2022, 09:14 PM
Last Post: kat417
  Updating nested dict list keys tbaror 2 1,313 Feb-09-2022, 09:37 AM
Last Post: tbaror
  Subclass initialized property used in parent class method. Is it bad coding practice? saavedra29 5 1,889 Feb-07-2022, 07:29 PM
Last Post: saavedra29
  Help Needed | Read Outlook email Recursively & download attachment Vinci141 1 4,137 Jan-07-2022, 07:38 PM
Last Post: cubangt
  changing key names in nested dict wardancer84 6 2,199 Sep-10-2021, 08:13 AM
Last Post: wardancer84
  Split dict of lists into smaller dicts of lists. pcs3rd 3 2,459 Sep-19-2020, 09:12 AM
Last Post: ibreeden
  use of subclass ebolisa 4 2,272 Sep-17-2020, 01:08 PM
Last Post: jefsummers

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020