我刚刚开始使用Python。我在我的应用程序中大量使用缓存,我的代码越来越多地使用相同的模式,这是我在整个商店中看到的标准缓存模式。在Python中是否有一些性感的语法技巧可以干掉一些这样的样板?
(顺便说一句,这不是实际代码)
# Determine if we are allowed to use cache
cacheable = settings.cache.lifetime is not None
# Generate unique cache key
cache_key = 'something_unique_{some_arg}'.format(some_arg=*args[0])
# Return cached version if allowed and available
if cacheable:
cached = memcache.get(cache_key)
if cached:
return cached
# Generate output
output = do_something_fooey(args[0])
# Cache output if allowed
if cacheable:
memcache.set(cache_key, output, settings.cache.lifetime)
return output
我也准备这样做,可能会写一个缓存包装函数并将输出生成作为"委托" (不知道如果那是Python的术语),但是从Python专家那里得到一些建议会很棒。
答案 0 :(得分:1)
你想要一个装饰者:
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.wraps
(http://docs.python.org/2/library/functools.html#functools.wraps)用于表现良好的装饰者。
答案 1 :(得分:1)
我发现了一些备用的预卷解决方案:
https://github.com/jayferd/python-cache 和 https://gist.github.com/abahgat/1395810
最后我创建了下面的内容,这是@ bruno的一个充实版本的例子。关于这个的好处是你可以将extra_key传递给装饰器,装饰器构成缓存键的一部分,可以是字符串或委托函数。 (生命周期也可以是委托函数或整数)。这允许您在运行时添加内容,例如通过用户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