I am creating a decorator to cache values of costly functions which can throw exceptions, and I want to record whether we reached the point where the value is initialized or not. As of now, I just initialize the value to an "odd" string new_val = "__THIS_IS_UNINITIALIZED__"
but that feels dirty.
I was wondering if using is
with a custom class (that doesn't do anything) would be safe.
This is what I have now:
class Cache:
_cached = {}
@staticmethod
def cache(prefix):
def wrapper(wrapped):
def inner(self, *args, **kwargs):
new_val = "__THIS_IS_UNINITIALIZED__"
key = Cache.make_key(*args, **kwargs)
if key in Cache._cached:
print("cache hit")
return Cache._cached[key]
print("cache miss")
try:
# This can throw exceptions
new_val = wrapped(self, *args, **kwargs)
# Something below this can ALSO throw
# exceptions, but the value has been
# initialized at this point.
except:
if new_val == "__THIS_IS_UNINITIALIZED__":
print("we never got to initialize :_( ")
else:
Cache._cache[key] = new_val
return inner
return wrapper
And I was wondering if I could use if is Class
instead of if new_val == "__THIS_IS_UNINITIALIZED__"
Something like this:
class Uninitialized:
pass
class Cache:
_cached = {}
@staticmethod
def cache(prefix):
def wrapper(wrapped):
def inner(self, *args, **kwargs):
new_val = Uninitialized
key = Cache.make_key(*args, **kwargs)
if key in Cache._cached:
print("cache hit")
return Cache._cached[key]
print("cache miss")
try:
# This can throw exceptions
new_val = wrapped(self, *args, **kwargs)
# Something below this can ALSO throw
# exceptions, but the value has been
# initialized at this point.
except:
if new_val is Uninitialized:
print("we never got to initialize :_( ")
else:
Cache._cache[key] = new_val
return inner
return wrapper
@staticmethod
def make_key(*args, **kwargs):
positional = ':'.join([str(s) for s in args])
kw = ':'.join('%s=%s' % kf for kv in kwargs.items())
return ':'.join([positional, kw])
class Test:
def __init__(self):
self.foo = 'hi'
@Cache.cache('api')
def test_cache(self, a, b):
raise Exception("foo")
if __name__ == "__main__":
t = Test()
t.test_cache(1, 2)
Using the string "__THIS_IS_UNINITIALIZED__"
works fine so far (and will work fine for the foreseeable future). This is mostly for learning purposes, to be honest.
Thank you in advance.