0

I'm working with a redis database and I'd like to integrate my prototype code to my baseline as seamlessly as possible so I'm trying to bury most of the inner workings with the interface from the python client to the redis server code into a few base classes that I will subclass throughout my production code.

I'm wondering if the assignment operator in python = is a callable and whether if it possible to modify the callable's pre and post behavior, particularly the post behavior such that I can call object.save() so that the redis cache would be updated behind the scenes without having to explicitly call it.

For example,

# using the redis-om module
from redis_om import JsonModel

kwargs = {'attr1': 'someval1', 'attr2': 'someval2'}
jsonModel = JsonModel(**kwargs)

# as soon as assignment completes, redis database 
# has the new value updated without needing to 
# call jsonModel.save()
jsonModel.attr1 = 'newvalue' 
larsks
  • 277,717
  • 41
  • 399
  • 399
LeanMan
  • 474
  • 1
  • 4
  • 18

1 Answers1

1

You can make such things with proxy class through __getattr__ and __setattr__ methods:

class ProxySaver:
    def __init__(self, model):
        self.__dict__['_model'] = model

    def __getattr__(self, attr):
        return getattr(self._model, attr)

    def __setattr__(self, attr, value):
        setattr(self._model, attr, value)
        self._model.save()

p = ProxySaver(jsonModel)
print(p.attr1)
p.attr1 = 'test'

But if attributes has a complex types (list, dict, objects, ... ), assignment for nested objects will not been detected and save call will be skipped (p.attr1.append('test'), p.attr1[0] = 'test2').

Stanislav Ivanov
  • 1,854
  • 1
  • 16
  • 22
  • Why would `p.attr1 = []` not be detected? This would go through __setattr__ afaik. I agree regarding the .append(). That will be missed. I wonder if its possible to detect changes/differences and then update those specific values. – LeanMan Aug 30 '22 at 02:25
  • 1
    @LeanMan Yes `p.attr1 = []` would be detected, but `p.attr1.append('test')` and `p.attr1[0]='test2'` would not. I was fix ambiguity in my answer. – Stanislav Ivanov Sep 02 '22 at 09:31
  • Thanks. Btw, do you know where the original implementation of __setattr__ can be found? Its possible by overriding it we are introducing an unintended behavior. I found this SO that uses `super().__setattr__(name, value)` which might be the preferred way to do it. Not sure. https://stackoverflow.com/questions/17020115/how-to-use-setattr-correctly-avoiding-infinite-recursion – LeanMan Sep 02 '22 at 22:07
  • So just realized this. The case for `p.attr1[0]='test2'` can be handled by `__getitem__` dunder method. I can probably create my own set of set, dict and list for all these collections and override the different methods required for the desired behavior. But the only thing I haven't figured out is access to the document in redis. `p` doesn't have the `.save()` method, its owner does. – LeanMan Sep 05 '22 at 15:12