Кэш файлов Python - PullRequest
       15

Кэш файлов Python

6 голосов
/ 24 марта 2012

Я создаю некоторые объекты из файлов (валидаторы из шаблонов xsd-файлов, чтобы собрать вместе другие xsd-файлы, как это происходит), и я хотел бы воссоздать объекты при изменении файла на диске.1002 * Я мог бы создать что-то вроде:

def getobj(fname, cache = {}):
    try:
        obj, lastloaded = cache[fname]
        if lastloaded < last_time_written(fname):
           # same stuff as in except clause
    except KeyError:
        obj = create_from_file(fname)
        cache[fname] = (obj, currenttime)

    return obj

Однако я бы предпочел использовать чужой проверенный код, если он существует.Есть ли существующая библиотека, которая делает что-то подобное?

Обновление : я использую python 2.7.1.

Ответы [ 3 ]

3 голосов
/ 24 марта 2012

Ваш код (включая логику кеша) выглядит нормально.

Рассмотрите возможность перемещения переменной cache за пределы определения функции. Это позволит добавить другие функции для очистки или проверки кэша.

Если вы хотите взглянуть на код, который делает нечто похожее, посмотрите на источник для модуля filecmp : http://hg.python.org/cpython/file/2.7/Lib/filecmp.py Интересная часть - как модуль stat используется для определения того, был ли файл изменен Вот функция подпись :

def _sig(st):
    return (stat.S_IFMT(st.st_mode),
            st.st_size,
            st.st_mtime)
1 голос
/ 24 марта 2012

Три мысли.

  1. Используйте try... except... else для более аккуратного потока управления.

  2. Время модификации файлаизвестно, что он нестабилен - в частности, он не обязательно соответствует последнему времени, когда файл был изменен!

  3. Python 3 содержит декоратор кэширования: functools.lru_cache.Вот источник.

    def lru_cache(maxsize=100):
        """Least-recently-used cache decorator.
    
        If *maxsize* is set to None, the LRU features are disabled and the cache
        can grow without bound.
    
        Arguments to the cached function must be hashable.
    
        View the cache statistics named tuple (hits, misses, maxsize, currsize) with
        f.cache_info().  Clear the cache and statistics with f.cache_clear().
        Access the underlying function with f.__wrapped__.
    
        See:  http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used
    
        """
        # Users should only access the lru_cache through its public API:
        #       cache_info, cache_clear, and f.__wrapped__
        # The internals of the lru_cache are encapsulated for thread safety and
        # to allow the implementation to change (including a possible C version).
    
        def decorating_function(user_function,
                    tuple=tuple, sorted=sorted, len=len, KeyError=KeyError):
    
            hits = misses = 0
            kwd_mark = (object(),)          # separates positional and keyword args
            lock = Lock()                   # needed because ordereddicts aren't threadsafe
    
            if maxsize is None:
                cache = dict()              # simple cache without ordering or size limit
    
                @wraps(user_function)
                def wrapper(*args, **kwds):
                    nonlocal hits, misses
                    key = args
                    if kwds:
                        key += kwd_mark + tuple(sorted(kwds.items()))
                    try:
                        result = cache[key]
                        hits += 1
                    except KeyError:
                        result = user_function(*args, **kwds)
                        cache[key] = result
                        misses += 1
                    return result
            else:
                cache = OrderedDict()       # ordered least recent to most recent
                cache_popitem = cache.popitem
                cache_renew = cache.move_to_end
    
                @wraps(user_function)
                def wrapper(*args, **kwds):
                    nonlocal hits, misses
                    key = args
                    if kwds:
                        key += kwd_mark + tuple(sorted(kwds.items()))
                    try:
                        with lock:
                            result = cache[key]
                            cache_renew(key)        # record recent use of this key
                            hits += 1
                    except KeyError:
                        result = user_function(*args, **kwds)
                        with lock:
                            cache[key] = result     # record recent use of this key
                            misses += 1
                            if len(cache) > maxsize:
                                cache_popitem(0)    # purge least recently used cache entry
                    return result
    
            def cache_info():
                """Report cache statistics"""
                with lock:
                    return _CacheInfo(hits, misses, maxsize, len(cache))
    
            def cache_clear():
                """Clear the cache and cache statistics"""
                nonlocal hits, misses
                with lock:
                    cache.clear()
                    hits = misses = 0
    
            wrapper.cache_info = cache_info
            wrapper.cache_clear = cache_clear
            return wrapper
    
        return decorating_function
    
1 голос
/ 24 марта 2012

Если нет особых причин использовать его в качестве аргумента, я бы использовал кеш как глобальный объект

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...