2014-09-05 4 views
0

У меня есть следующий декоратор в моем сценарии:Python общего назначения кэширования декоратор

def cached_to_disk(func): 
    """Save the results of the func to the directory specified in datadir.""" 
    path = datadir + func.__name__ 
    if not os.path.exists(path): 
     os.makedirs(path) 

    @wraps(func) 
    def cached_func(page): 
     fullpath = "{}/{}".format(path, page.url) 
     if os.path.isfile(fullpath): 
      with open(fullpath) as cached_file: 
       data = cached_file.read() 
     else: 
      data = func(page) 
      if data is not None: 
       with open(fullpath, "w") as cached_file: 
        cached_file.write(data) 
     return data 
    return cached_func 

Он прекрасно работает. Однако теперь я хочу расширить его работу для любой функции. В некотором роде:

@wraps(func) 
def cached_func(*args, **kwargs): 
    pass 

Проблема, с которой я столкнулась, определяет, где сохранить кеш. Когда я работаю с собственными объектами страницы, я могу просто использовать (нормализованный) URL-адрес в качестве имени файла. Однако, когда func может принимать произвольные параметры, не так ясно, как определить имя файла. Я думал об использовании args[0].__repr__, но это не очень хорошая идея для функций с несколькими аргументами (например, download(site, page_on_the_site)) или без каких-либо аргументов.

В идеале, я бы хотел, чтобы декоратор общего назначения продолжал работать точно так же для тех функций, которые он уже поддерживает.

Есть ли простой и надежный способ сделать что-то подобное?

+1

Вы можете создать кэш-ключ с помощью хэширования позиционного и ключевого аргументов. Смотрите [Py2.6 + и Py3.0 + обратный путь LRU Cache Python 3.3] (http://code.activestate.com/recipes/578078-py26-and-py30-backport-of-python-33s- lru-cache /) для примера (строка 17). –

ответ

0

Существует не простое решение, которое работает для любых аргументов. Вам нужно будет последовательно сериализовать аргументы, и не все аргументы могут быть сериализованы (например, закрытие обычно сложно). Посмотрите на модуль shelve для чего-то близкого.

Это в основном дает вам словарь-подобный объект, а любой объект, который можно мариновать, можно использовать в качестве ключа, поэтому вы можете использовать что-то вроде (func.__name__, args, kwargs).

Обратите внимание, что это более общий, чем использование словаря Python, который требует, чтобы ключи были хешируемыми.

Смежные вопросы