1

我刚刚开始使用 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 获得一些建议会很棒专家。

4

2 回答 2

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.wrapshttp://docs.python.org/2/library/functools.html#functools.wraps)作为表现良好的装饰器。

于 2013-05-23T11:52:23.373 回答
1

我发现了几个替代的预卷解决方案:

https://github.com/jayferd/python-cachehttps://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
于 2013-05-23T21:03:23.030 回答