Я создаю декоратор для кэширования значений дорогостоящих функций, которые могут генерировать исключения, и я хочу записать, достигли ли мы точки, где значение инициализировано или нет.На данный момент я просто инициализирую значение «нечетной» строкой new_val = "__THIS_IS_UNINITIALIZED__"
, но чувствует себя грязным .
Мне было интересно, если использовать is
с пользовательским классом (который неничего не делать) будет безопасно.
Вот что у меня сейчас:
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
И мне было интересно, смогу ли я использовать if is Class
вместо if new_val == "__THIS_IS_UNINITIALIZED__"
Примерно так:
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)
Использование строки "__THIS_IS_UNINITIALIZED__"
пока отлично работает (и будет работать в обозримом будущем).Честно говоря, это в основном для целей обучения.
Заранее спасибо.