Я унаследовал кучу устаревшего кода и столкнулся с проблемой.Я полагаю, что идея, которая здесь была предпринята, состояла в том, чтобы использовать контейнерный кэш, такой как redis, для хранения определенных атрибутов, которые будут совместно использоваться многими процессами.Помимо того, был ли это лучший способ выполнить задачу, я наткнулся на то, что меня смутило.Если методы __getattribute__
и __setattr__
переопределены, как показано ниже, атрибуты изменяемого экземпляра не могут быть обновлены.Я ожидал бы, что изменения, сделанные в self.b
, будут отражены в вызове print()
, но, как вы можете видеть из вывода, печатается только исходный пустой словарь.Переход по строке self.b["foo"] = "bar"
показывает, что сделан вызов __getattribute__
, и из кэша извлечен правильный объект, но не сделан вызов __setattr__
, и словарь, похоже, не обновляется каким-либо образом.У кого-нибудь есть идеи, почему это может быть?
import dill
_reserved_fields = ["this_is_reserved"]
class Cache:
_cache = {}
def get(self, key):
try:
return self._cache[key]
except KeyError:
return None
def set(self, key, value):
self._cache[key] = value
def exists(self, key):
return key in self._cache
class Class(object):
def __init__(self, cache):
self.__dict__['_cache'] = cache
self.a = 1
self.a = 2
print(self.a)
self.b = dict()
self.b["foo"] = "bar" # these changes aren't set in the cache and seem to disappear
print(self.b)
self.this_is_reserved = dict()
self.this_is_reserved["reserved_field"] = "value" # this updates fine
print(self.this_is_reserved)
def __getattribute__(self, item):
try:
return object.__getattribute__(self, item)
except AttributeError:
key = "redis-key:" + item
if not object.__getattribute__(self, "_cache").exists(key):
raise AttributeError
else:
obj = object.__getattribute__(self, "_cache").get(key)
return dill.loads(obj)
def __setattr__(self, key, value):
if key in _reserved_fields:
self.__dict__[key] = value
elif key.startswith('__') and key.endswith('__'):
super().__setattr__(key, value)
else:
value = dill.dumps(value)
key = "redis-key:" + key
self._cache.set(key, value)
if __name__ == "__main__":
cache = Cache()
inst = Class(cache)
# output
# 2
# {}
# {'reserved_field': 'value'}