Cache de arquivos em Python

Eu estou criando alguns objects de arquivos (validadores de modelos de arquivos xsd, para juntar outros arquivos xsd, como isso acontece), e gostaria de recriar os objects quando o arquivo no disco é alterado.

Eu poderia criar algo como:

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 

No entanto, eu preferiria usar o código testado de outra pessoa, se existir. Existe uma biblioteca existente que faz algo assim?

Atualização : Estou usando o python 2.7.1.

Seu código (incluindo a lógica do cache) parece bem.

Considere mover a variável de cache fora da definição da function. Isso tornará possível adicionar outras funções para limpar ou inspecionar o cache.

Se você quiser ver o código que faz algo semelhante, veja a fonte do módulo filecmp : http://hg.python.org/cpython/file/2.7/Lib/filecmp.py A parte interessante é como o módulo stat é usado para determinar se um arquivo foi alterado. Aqui está a function de assinatura :

 def _sig(st): return (stat.S_IFMT(st.st_mode), st.st_size, st.st_mtime) 

A menos que haja uma razão específica para usá-lo como argumento, eu usaria o cache como um object global

Três pensamentos.

  1. Use try... except... else para um stream de controle mais limpo.

  2. Os tempos de modificação de arquivos são notoriamente instáveis ​​- em particular, eles não correspondem necessariamente à hora mais recente em que o arquivo foi modificado!

  3. O Python 3 contém um decorador de armazenamento em cache: functools.lru_cache . Aqui está a fonte.

     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