Python 使用缓存的\u属性捕获异常
我正在尝试使用Python 使用缓存的\u属性捕获异常,python,python-decorators,python-descriptors,Python,Python Decorators,Python Descriptors,我正在尝试使用装饰器捕获缓存的\u属性的异常 我想做一些简单的事情如下,但这不起作用 from pprint import pprint import time from cached_property import cached_property class MyException(Exception): pass def catch_my_exceptions(fn): def wrapped(*args, **kwargs): try:
装饰器捕获缓存的\u属性的异常
我想做一些简单的事情如下,但这不起作用
from pprint import pprint
import time
from cached_property import cached_property
class MyException(Exception):
pass
def catch_my_exceptions(fn):
def wrapped(*args, **kwargs):
try:
return fn(*args, **kwargs)
except MyException as e:
cls = args[0]
err = 'Found error at {}: {}'.format(time.asctime(), e)
cls.error_msgs.append(err)
print(err)
return
return wrapped
class Foo(object):
def __init__(self):
self.vars = {}
@cached_property
@catch_my_exceptions
def is_cache_working(self):
self.vars[time.asctime()] = True
time.sleep(3)
print('running cache runner')
return time.asctime()
fo = Foo()
for i in range(3):
print(fo.is_cache_working)
pprint(fo.vars)
# This doesn't trigger caching
running cache runner
Thu Feb 23 21:45:15 2017
{'Thu Feb 23 21:45:11 2017': True}
running cache runner
Thu Feb 23 21:45:18 2017
{'Thu Feb 23 21:45:11 2017': True, 'Thu Feb 23 21:45:15 2017': True}
running cache runner
Thu Feb 23 21:45:21 2017
{'Thu Feb 23 21:45:11 2017': True,
'Thu Feb 23 21:45:15 2017': True,
'Thu Feb 23 21:45:18 2017': True}
# Current solution that works:
我的解决办法是做以下几点。有人能给我建议一个更好的方法吗。另外,我如何将异常列表传递给此my\u cached\u decorator
import time
from pprint import pprint
from cached_property import cached_property
class MyException(Exception):
pass
class my_cached_property(cached_property):
def __init__(self, func):
super(self.__class__, self).__init__(func)
def __get__(self, obj, cls):
try:
super(self.__class__, self).__get__(obj, cls)
except MyException as e:
err = 'Found error at {}: {}'.format(time.asctime(), e)
print(err)
value = obj.__dict__[self.func.__name__] = None
return value
class Foo(object):
def __init__(self):
self.vars = {}
@my_cached_property
def is_cache_working(self):
self.vars[time.asctime()] = True
time.sleep(3)
print('running cache runner')
raise MyException('fooobar')
return time.asctime()
fo = Foo()
for i in range(3):
print(fo.is_cache_working)
pprint(fo.vars)
这可能不是最好的解决方案,但您可以访问从装饰器返回给调用方的内部函数,也可以访问装饰器闭包中的内部函数
例如:
def decorator(f):
def wrapper(*args, **kwargs):
try:
f(*args, **kwargs)
except Exception as e:
wrapper.__dict__.setdefault('errors', []).append(e)
return wrapper
@decorator
def raiser():
raise Exception('Oh no!')
> raiser()
> raiser.errors
[Exception('Oh no!')]
好吧,我发现了问题所在,这就是缓存_属性的工作方式。为了缓存它,它将值写入实例,并使用与它包装的函数相同的名称。问题是,它所包装的函数的名称具有来自装饰程序的名称“wrapped”。因此,如果在初始fo.is_cache_工作之后访问fo.wrapped,您将得到缓存结果
要把这两种想法混合在一起是不容易的。最简单的解决方案是编写自己的缓存_属性,将值存储在自身上:
class cached_property(object):
def __init__(self, func):
self.func = func
# you can store other function attributes here - such as __doc__ - if you want
self.values = {}
def __get__(self, instance, owner):
if instance in self.values:
return self.values[instance]
else:
value = self.values[instance] = self.func(instance)
return value
或者,在decorator中,使用functools.wrapps
decorator来修饰wrapped
函数。因此,将导入添加到顶部的functools
,并在wrapped
定义之前的行中添加functools.wrapps(fn)
。这会将wrapped
的\uuu名称\uuuu
更改为与fn
同名,以及其他一些内容。