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
  Convert nested sample json api data into csv in python shantanu97 3 2,808 May-21-2022, 01:30 PM
Last Post: deanhystad
  How to return the next page from json recursively? sandson 0 1,147 Apr-01-2022, 11:01 PM
Last Post: sandson
  Convert python dataframe to nested json kat417 1 6,329 Mar-18-2022, 09:14 PM
Last Post: kat417
  Updating nested dict list keys tbaror 2 1,276 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,762 Feb-07-2022, 07:29 PM
Last Post: saavedra29
  Help Needed | Read Outlook email Recursively & download attachment Vinci141 1 4,075 Jan-07-2022, 07:38 PM
Last Post: cubangt
  changing key names in nested dict wardancer84 6 2,142 Sep-10-2021, 08:13 AM
Last Post: wardancer84
  Split dict of lists into smaller dicts of lists. pcs3rd 3 2,368 Sep-19-2020, 09:12 AM
Last Post: ibreeden
  use of subclass ebolisa 4 2,217 Sep-17-2020, 01:08 PM
Last Post: jefsummers
  Convert xml to dict and group data and sum totals kashcode 5 2,391 Aug-16-2020, 01:04 AM
Last Post: scidam

Forum Jump:

User Panel Messages

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