Python中的De-uglify memcache样板文件
我刚刚开始学习Python。我在我的应用程序中大量使用缓存,我的代码中也越来越多地使用这种模式,这是我在商店里看到的标准缓存模式。Python中是否有一些性感的语法技巧可以让这个样板文件干涸 (顺便说一句,这不是实际代码) 我也将尝试一下,可能会编写一个缓存包装器函数,并将输出生成作为“委托”传递给它(如果这是Python行话,则不知道),但最好从Python专家那里得到一些建议。您想要一个装饰器:Python中的De-uglify memcache样板文件,python,caching,boilerplate,Python,Caching,Boilerplate,我刚刚开始学习Python。我在我的应用程序中大量使用缓存,我的代码中也越来越多地使用这种模式,这是我在商店里看到的标准缓存模式。Python中是否有一些性感的语法技巧可以让这个样板文件干涸 (顺便说一句,这不是实际代码) 我也将尝试一下,可能会编写一个缓存包装器函数,并将输出生成作为“委托”传递给它(如果这是Python行话,则不知道),但最好从Python专家那里得到一些建议。您想要一个装饰器: def cached(func): def _cached(*args):
def cached(func):
def _cached(*args):
# Determine if we are allowed to use cache
cacheable = settings.cache.lifetime is not None
# Generate unique cache key
cache_key = '{0}-{1}-{2}'.format(func.__module__, func.__name__, args[0])
# Return cached version if allowed and available
if cacheable:
result = memcache.get(cache_key)
if result is not None:
return result
# Generate output
result = func(args[0])
# Cache output if allowed
if cacheable and result is not None:
memcache.set(cache_key, result, settings.cache.lifetime)
return result
return _cached
@cached
def do_something_fooey(*args):
return something
您可能希望使用
functools.wrapps
()作为性能良好的装饰程序。我找到了两种备用的预卷解决方案:
和
最后,我创建了以下内容,这是@bruno示例的充实版本。这个函数的好处在于,您可以将一个额外的_键传递给decorator,decorator是缓存键的一部分,可以是字符串或委托函数。(生存期也可以是委托函数或整数)。这允许您在运行时添加内容,例如按用户id唯一地进行缓存
def cached(lifetime=settings.cache.default_lifetime, extra_key=None):
def _cached(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# Resolve lifetime if it's a function
resolved_lifetime = lifetime(*args) if hasattr(lifetime, '__call__') else lifetime
if resolved_lifetime is not None:
# Hash function args
items = kwargs.items()
items.sort()
hashable_args = (args, tuple(items))
args_key = hashlib.md5(pickle.dumps(hashable_args)).hexdigest()
# Generate unique cache key
cache_key = '{0}-{1}-{2}-{3}'.format(
func.__module__,
func.__name__,
args_key,
extra_key() if hasattr(extra_key, '__call__') else extra_key
)
# Return cached version if allowed and available
result = memcache.get(cache_key)
if result is not None:
return result
# Generate output
result = func(*args, **kwargs)
# Cache output if allowed
if resolved_lifetime is not None and result is not None:
memcache.set(cache_key, result, resolved_lifetime)
return result
return wrapper
return _cached
谢谢@bruno,这看起来不错。我能在调料中再加些别的吗?让我们假设缓存密钥无法推断,但必须根据具体情况动态生成。例如,我可能希望按用户分别缓存对象,因此我希望将用户id混合到密钥中。你将如何与你的装饰师一起实现这一目标?@Ash:没有装饰师,你将如何获得这些信息?请记住,使用此装饰器,装饰后的函数将被包装器函数(
\u cached
在上面)替换,因此包装器可以访问所有参数。我将此标记为答案,并添加了我自己的答案,从而充实了此答案。我最终将此结果应用到我的Google App Engine开源样板中,因此,有关一个工作示例(和性感样板),请参见
def cached(lifetime=settings.cache.default_lifetime, extra_key=None):
def _cached(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# Resolve lifetime if it's a function
resolved_lifetime = lifetime(*args) if hasattr(lifetime, '__call__') else lifetime
if resolved_lifetime is not None:
# Hash function args
items = kwargs.items()
items.sort()
hashable_args = (args, tuple(items))
args_key = hashlib.md5(pickle.dumps(hashable_args)).hexdigest()
# Generate unique cache key
cache_key = '{0}-{1}-{2}-{3}'.format(
func.__module__,
func.__name__,
args_key,
extra_key() if hasattr(extra_key, '__call__') else extra_key
)
# Return cached version if allowed and available
result = memcache.get(cache_key)
if result is not None:
return result
# Generate output
result = func(*args, **kwargs)
# Cache output if allowed
if resolved_lifetime is not None and result is not None:
memcache.set(cache_key, result, resolved_lifetime)
return result
return wrapper
return _cached