我正在研究一个表示具有大量相关数据的对象的类。我将这些数据存储在名为metadata的字典类属性中。表示形式可以是:
{'key1':slowToComputeValue, 'key2':evenSlowerToComputeValue}
在某些情况下,值的计算非常慢,因此我想做的是使用“ getter”函数,首先尝试从元数据字典中获取值。仅在KeyError上(即,当getter尝试获取尚不存在的键的值时),才应计算该值(并将其添加到字典中,以便在下次调用getter时进行快速访问)。
我从一个简单的开始:
try:
return self.metadata[requested_key]
except KeyError:
#Implementation of function
由于班上有许多吸气剂,我开始认为这头三行代码可以由装饰器处理。但是我在使这项工作中遇到问题。问题是我需要将元数据字典从类实例传递给装饰器。我发现了一些类似这样的教程和帖子,它们表明可以将参数发送到封闭函数,但是我遇到的困难是向其发送类实例化属性元数据(如果我发送字符串值,则可以工作) )。
我尝试的一些示例代码在这里:
def get_existing_value_from_metadata_if_exists(metadata):
def decorator(function):
@wraps(function)
def decorated(*args, **kwargs):
function_name = function.__name__
if function_name in metadata.keys():
return metadata[function_name]
else:
function(*args, **kwargs)
return decorated
return decorator
class my_class():
@get_existing_value_from_metadata_if_exists(metadata)
def get_key1(self):
#Costly value calculation and add to metadata
@get_existing_value_from_metadata_if_exists(metadata)
def get_key2(self):
#Costly value calculation and add to metadata
def __init__(self):
self.metadata = {}
我遇到的错误通常是无法自定义的,但是我尝试了参数放置,装饰器放置等的各种组合,但均未成功。
所以我的问题是:
是的,装饰器是一个很好的用例。例如Django,已经包含了类似的东西,称为cached_property
。
基本上,它所做的就是,当第一次访问该属性时,它将__dict__
以与函数相同的名称将数据存储在实例的dict()中。当我们稍后获取相同的属性时,简单地从实例字典中获取值。
Acached_property
是一个非数据描述符。因此,一旦在实例的字典中设置了键,对属性的访问将始终从那里获取值。
class cached_property(object):
"""
Decorator that converts a method with a single self argument into a
property cached on the instance.
Optional ``name`` argument allows you to make cached properties of other
methods. (e.g. url = cached_property(get_absolute_url, name='url') )
"""
def __init__(self, func, name=None):
self.func = func
self.__doc__ = getattr(func, '__doc__')
self.name = name or func.__name__
def __get__(self, instance, cls=None):
if instance is None:
return self
res = instance.__dict__[self.name] = self.func(instance)
return res
在您的情况下:
class MyClass:
@cached_property
def key1(self):
#Costly value calculation and add to metadata
@cached_property
def key2(self):
#Costly value calculation and add to metadata
def __init__(self):
# self.metadata not required
使用name
参数将现有方法转换为缓存的属性。
class MyClass:
def __init__(self, data):
self.data = data
def get_total(self):
print('Processing...')
return sum(self.data)
total = cached_property(get_total, 'total')
演示:
>>> m = MyClass(list(range(10**5)))
>>> m.get_total()
Processing...
4999950000
>>> m.total
Processing...
4999950000
>>> m.total
4999950000
>>> m.data.append(1000)
>>> m.total # This is now invalid
4999950000
>>> m.get_total() # This still works
Processing...
4999951000
>>> m.total
4999950000
根据上面的示例,我们可以total
知道只要内部数据尚未更新就可以使用,从而节省了处理时间。但这并没有get_total()
多余,因为它可以根据数据获得正确的总数。
另一个示例可能是,get_full_name()
到目前为止,我们面向公众的客户一直使用某物(例如)作为方法,但我们意识到将它用作属性(仅full_name
)是更合适的,在这种情况下,保持该方法完好无损,但将其标记为已弃用,并从现在开始建议用户使用新属性。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句