2009-09-15 13 views
84

Estoy buscando una biblioteca de caché de Python pero no puedo encontrar nada hasta el momento. Necesito una interfaz simple como dict, donde puedo establecer las claves y su vencimiento y recuperarlas en caché. Una especie de algo como:¿Hay una biblioteca de almacenamiento en caché de Python?

cache.get(myfunction, duration=300) 

que me dará el elemento de la caché si existe o llamar a la función y almacenarla si no lo hace o ha caducado. ¿Alguien sabe algo como esto?

+0

Creo que le falta 'elemento 'en su ejemplo. – SilentGhost

+0

python 2.xo 3.x? –

+0

Sí, esto probablemente necesitaría una clave ... Y, 2.x. –

Respuesta

8

Creo the python memcached API es la herramienta frecuente, pero no he utilizado yo mismo y no soy seguro si es compatible con las características que necesita.

+3

Ese es el estándar de la industria, pero todo lo que quiero es un mecanismo de almacenamiento en la memoria simple que puede contener 100 teclas más o menos, y memcached es un poco exagerado. Gracias por la respuesta, sin embargo. –

6
import time 

class CachedItem(object): 
    def __init__(self, key, value, duration=60): 
     self.key = key 
     self.value = value 
     self.duration = duration 
     self.timeStamp = time.time() 

    def __repr__(self): 
     return '<CachedItem {%s:%s} expires at: %s>' % (self.key, self.value, time.time() + self.duration) 

class CachedDict(dict): 

    def get(self, key, fn, duration): 
     if key not in self \ 
      or self[key].timeStamp + self[key].duration < time.time(): 
       print 'adding new value' 
       o = fn(key) 
       self[key] = CachedItem(key, o, duration) 
     else: 
      print 'loading from cache' 

     return self[key].value 



if __name__ == '__main__': 

    fn = lambda key: 'value of %s is None' % key 

    ci = CachedItem('a', 12) 
    print ci 
    cd = CachedDict() 
    print cd.get('a', fn, 5) 
    time.sleep(2) 
    print cd.get('a', fn, 6) 
    print cd.get('b', fn, 6) 
    time.sleep(2) 
    print cd.get('a', fn, 7) 
    print cd.get('b', fn, 7) 
+5

Hice algo así, pero necesita bloqueos para multihilo y un parámetro de tamaño para evitar que crezca infinitamente. Luego necesita alguna función para ordenar las claves mediante accesos para descartar las menos accesibles, etc. etc ... –

+0

La línea __repr__ es incorrecta (debería usar self.timeStamp). Además, es una implementación deficiente que innecesariamente hace matemáticas para cada get(). El tiempo de caducidad debe calcularse en el inicio de CachedItem. – ivo

+0

De hecho, si solo está implementando el método 'get', esto no debería ser una subclase dict, debería ser un objeto con un dict incrustado. – ivo

25

También puede echar un vistazo a la Memoize decorator. Probablemente puedas lograr que haga lo que quieras sin demasiadas modificaciones.

+0

Eso es inteligente. Unos pocos cambios y el decorador incluso podría caducar después de un tiempo establecido. –

+0

Definitivamente podría escribir un límite basado en el espacio para la memoria caché en el decorador. Eso sería útil si quisiera una función para, por ejemplo, generar la secuencia de fibonacci término por término. Desea almacenar en caché, pero solo necesita los dos últimos valores; guardarlos es solo espacio ineficiente. – reem

1

Mira gocept.cache

5

Pruebe redis, es una de las soluciones más sencillas y limpias para que las aplicaciones compartan datos de forma atómica o si tiene alguna plataforma de servidor web. Es muy fácil de configurar, necesitará un cliente python redis http://pypi.python.org/pypi/redis

4

Puede usar mi solución simple para el problema. Que es realmente sencillo, nada del otro mundo:

class MemCache(dict): 
    def __init__(self, fn): 
     dict.__init__(self) 
     self.__fn = fn 

    def __getitem__(self, item): 
     if item not in self: 
      dict.__setitem__(self, item, self.__fn(item)) 
     return dict.__getitem__(self, item) 

mc = MemCache(lambda x: x*x) 

for x in xrange(10): 
    print mc[x] 

for x in xrange(10): 
    print mc[x] 

De hecho, carece de funcionalidad de caducidad, pero se puede ampliar fácilmente con la especificación de una regla particular en Memcache c-tor.

El código de esperanza es bastante fácil de entender, pero si no, solo mencionar que a esa caché se le está pasando una función de traducción como uno de sus parámetros c-tor. Se usa a su vez para generar salida en caché con respecto a la entrada.

creo que sirve

+1

+1 por sugerir algo simple. Dependiendo del problema, podría ser la herramienta para el trabajo. PD No necesita el 'else' en' __getitem__' :) – hiwaylon

+0

¿Por qué no necesitaría '' 'else''' en' '' __getitem__'''? Ahí es donde puebla el dict ... –

13

JOBLIBhttp://packages.python.org/joblib/ es compatible con funciones de almacenamiento en caché en el patrón memoize. En su mayoría, la idea es almacenar en caché las funciones computacionalmente costosas.

>>> from joblib import Memory 
>>> mem = Memory(cachedir='/tmp/joblib') 
>>> import numpy as np 
>>> square = mem.cache(np.square) 
>>> 
>>> a = np.vander(np.arange(3)).astype(np.float) 
>>> b = square(a)         
________________________________________________________________________________ 
[Memory] Calling square... 
square(array([[ 0., 0., 1.], 
     [ 1., 1., 1.], 
     [ 4., 2., 1.]])) 
___________________________________________________________square - 0...s, 0.0min 

>>> c = square(a) 

También puede hacer cosas sofisticadas como usar el decorador @ memory.cache en las funciones. La documentación está aquí: http://packages.python.org/joblib/memory.html

+2

Como nota al margen, joblib realmente brilla cuando se trabaja con grandes matrices NumPy, ya que tiene métodos especiales para tratar con ellos específicamente. – alexbw

-3

keyring es la mejor biblioteca de caché de python. Puede utilizar

keyring.set_password("service","jsonkey",json_res) 

json_res= keyring.get_password("service","jsonkey") 

json_res= keyring.core.delete_password("service","jsonkey") 
+0

Esa es una biblioteca de claves, no una biblioteca de almacenamiento en caché. –

+0

@StavrosKorokithakis En realidad, implementé el almacenamiento en caché de claves a través del llavero – imp

41

Desde Python 3.2 se puede utilizar el decorador @lru_cache de la biblioteca functools. Es un último caché utilizado recientemente, por lo que no hay tiempo de caducidad para los elementos, pero como un hack rápido es muy útil.

from functools import lru_cache 

@lru_cache(maxsize=256) 
def f(x): 
    return x*x 

for x in range(20): 
    print f(x) 
for x in range(20): 
    print f(x) 
+12

[cachetools] (https://pypi.python.org/pypi/cachetools) ofrece una buena implementación de estos y es compatible con python 2 y python 3. – vaab

+0

grande +1 para cachetools ... parece muy bueno y tiene un par de algoritmos más de caché :) –

+0

cachetools no es seguro para subprocesos aunque – roboslone

Cuestiones relacionadas