2009-09-15 11 views
84

Sto cercando una libreria di cache di Python ma non riesco a trovare nulla finora. Ho bisogno di una semplice interfaccia dict -like dove posso impostare le chiavi e la loro scadenza e recuperarle nella cache. Un po 'qualcosa di simile:Esiste una libreria di caching Python?

cache.get(myfunction, duration=300) 

che mi darà la voce dalla cache se esiste o chiamare la funzione e conservarlo se lo fa non è o è scaduta. Qualcuno sa qualcosa del genere?

+0

penso che manchi 'item' nel tuo esempio. – SilentGhost

+0

python 2.xo 3.x? –

+0

Sì, probabilmente sarebbe necessaria una chiave ... E, 2.x. –

risposta

8

Credo the python memcached API è lo strumento prevalente, ma non l'ho usato io stesso e non sono sicuro se supporta le funzionalità necessarie.

+3

Quello è lo standard del settore, ma tutto quello che voglio è un semplice meccanismo di memoria in-memory che può contenere 100 tasti o giù di lì, e memcached è un po 'eccessivo. Grazie per la risposta, però. –

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

Ho fatto qualcosa del genere, ma hai bisogno di lock per il multithreading e un parametro size per evitare che cresca all'infinito. Quindi hai bisogno di qualche funzione per ordinare le chiavi tramite gli accessi per scartare quelli meno accessibili, ecc. Ecc ... –

+0

La riga __repr__ non è corretta (dovrebbe usare self.timeStamp). Inoltre è una cattiva implementazione che inutilmente fa matematica per ogni get(). Il tempo di scadenza deve essere calcolato nel CachedItem init. – ivo

+0

Infatti, se stai implementando solo il metodo 'get', questa non dovrebbe essere una sottoclasse dict, dovrebbe essere un oggetto con un dettato incorporato. – ivo

25

Si potrebbe anche dare un'occhiata al Memoize decorator. Probabilmente potresti farlo fare ciò che vuoi senza troppe modifiche.

+0

È intelligente. Alcune modifiche e il decoratore potrebbe anche scadere dopo un tempo prestabilito. –

+0

Si potrebbe sicuramente scrivere un limite spaziale alla cache nel decoratore. Ciò sarebbe utile se si desidera che una funzione, ad esempio, generi la sequenza di Fibonacci termine per termine. Vuoi la memorizzazione nella cache, ma hai solo bisogno degli ultimi due valori - il salvataggio di tutti è solo uno spazio inefficiente. – reem

1

Guarda gocept.cache

5

Try redis, è una delle soluzioni più semplici e pulite per le applicazioni per condividere dati in modo atomico o se si dispone di una piattaforma di server web. È molto facile da configurare, è necessario un client python redis http://pypi.python.org/pypi/redis

4

È possibile utilizzare la mia soluzione semplice al problema. E 'davvero semplice, niente di speciale:

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] 

Manca infatti la scadenza funcionality, ma si può facilmente estendere con specificando una particolare regola in MemCache c-tor.

Il codice di speranza è abbastanza auto-esplicativo, ma in caso contrario, solo per citare, quella cache viene passata una funzione di traduzione come uno dei suoi parametri c-tor. A sua volta è usato per generare output in cache per quanto riguarda l'input.

Speranza che aiuta

+1

+1 per suggerire qualcosa di semplice. A seconda del problema, potrebbe essere solo lo strumento per il lavoro. Post scriptum Non è necessario il 'else' in' __getitem__' :) – hiwaylon

+0

Perché non avrebbe bisogno di '' else''' nel '' '__getitem__'''? È qui che inserisce la dict ... –

13

Joblibhttp://packages.python.org/joblib/ supporta le funzioni di caching nel modello Memoize. Principalmente, l'idea è di memorizzare le funzioni computazionalmente costose.

>>> 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) 

Puoi anche fare cose di fantasia come usare il decoratore @ memory.cache sulle funzioni. La documentazione è qui: http://packages.python.org/joblib/memory.html

+2

Come sidenote, joblib brilla davvero quando si lavora con grandi array NumPy, poiché ha metodi speciali per gestirli in modo specifico. – alexbw

-3

keyring è la migliore libreria di cache di Python. È possibile utilizzare

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

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

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

Questa è una libreria di chiavi, non una libreria di memorizzazione nella cache. –

+0

@StavrosKorokithakis In realtà, ho implementato il caching delle chiavi attraverso il portachiavi – imp

41

Da Python 3.2 è possibile utilizzare il decoratore @lru_cache dalla libreria functools. Si tratta di una cache utilizzata di recente, quindi non c'è tempo di scadenza per gli elementi in essa contenuti, ma come un attacco rapido è molto utile.

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) offre una buona implementazione di questi ed è compatibile con python 2 e python 3. – vaab

+0

grande +1 per cachetools ... sembra abbastanza bello e ha un paio di altri algoritmi di cache :) –

+0

cachetools non è thread-safe anche se – roboslone

Problemi correlati