Uso
Cache¶
Um cache em memória está disponível para funções síncronas e assíncronas. Porém, é fundamental destacar que o cache será zerado ou limpo sempre que o programa for interrompido.
from cachetoolz import cache
# O import acima é equivalente a isso
from cachetoolz import AsyncInMemory, Cache
cache = Cache(AsyncInMemory())
@cache()
def sub(x, y):
return x - y
@cache()
async def mul(x, y):
return x * y
Armazena em cache uma chamada de função e a armazena no namespace.
O decorador simples, @cache, é suportado, bem como uma chamada com argumentos de palavra-chave @cache(ttl=7200).
| Parâmetro | Tipo | Descrição | Padrão |
|---|---|---|---|
backend |
Union[AsyncBackendABC, BackendABC] | Backend de cache | obrigatório |
Com backend assíncrono redis
from cachetoolz import AsyncRedisBackend, Cache
cache = Cache(AsyncRedisBackend())
Com backend sincrono redis
from cachetoolz import RedisBackend, Cache
cache = Cache(RedisBackend())
Para obter mais detalhes sobre backends, consulte a seção backends.
@cache¶
| Parâmetro | Tipo | Descrição | Padrão |
|---|---|---|---|
ttl |
int, float, timedelta |
cache ttl (tempo de vida) | math.inf |
namespace |
str |
namespace para cache | "default" |
typed |
bool |
Se typed for definido como True, argumentos de função de tipos diferentes serão armazenados em cache separadamente | False |
keygen |
cachetoolz.types.KeyGenerator |
função para gerar uma chave identificadora de cache | cachetoolz.utils.default_keygen |
Exemplos:
Um cache simples
>>> @cache
def func(*args, **kwargs):
...
Especifique um namespace
@cache(namespace='bar')
def func(*args, **kwargs):
...
Defina um tempo de expiração em segundos
@cache(ttl=60)
def func(*args, **kwargs):
...
Use timedelta para definir a expiração
from datetime import timedelta
@cache(ttl=timedelta(days=1))
def func(*args, **kwargs):
...
Diferencie o cache com base nos tipos de argumento
@cache(typed=True)
def func(*args, **kwargs):
...
Usando um keygen personalizado
def custom_keygen(
typed: bool, func: Func, *args: P.args, **kwargs: P.kwargs
) -> str:
"""
Construa uma chave para uma função.
Parameters
----------
typed
Se typed for definido como True, argumentos de função
de tipos diferentes serão armazenados em cache separadamente.
func
Função
args
Argumentos posicionais de função.
kwargs
Argumentos nomeados de função.
Returns
-------
Chave identificadora de cache.
"""
@cache(keygen=custom_keygen)
def func(*args, **kwargs):
...
Altere o backend de cache que será usado em uma função específica
@cache(backend=RedisBackend())
def func(): ...
@cache.clear¶
Limpa todos os caches de todos os namespaces.
Este decorador limpará todos os caches contidos nos namespaces especificados assim que a função decorada for executada.
| Parâmetro | Tipo | Descrição | Padrão |
|---|---|---|---|
namespaces |
Sequence[str] |
namespaces a ser limpos. | ('default',) |
Exemplos:
Um cache simples e limpo
@cache.clear
def func(*args, **kwargs):
...
Definindo os namespaces a serem limpos
@cache.clear(namespaces=['foo'])
def func(*args, **kwargs):
...
Altere o backend clear que será usado em uma função específica
@cache.clear(backend=RedisBackend())
def func(): ...
Backend¶
Em Memória¶
Estão disponíveis backends na memória síncronos e assíncronos. Apenas instancie-os, eles não precisam de parâmetros.
from cachetoolz import AsyncInMemory, InMemory
async_in_memory = AsyncInMemory()
sync_in_memory = InMemory()
Funções assíncronas podem ser decoradas quando o backend síncrono está sendo usado, mas é importante ter cuidado, pois pode haver possíveis erros ou inconsistências ao tentar acessar o backend.
Redis¶
Com o Redis, você tem a flexibilidade de escolher entre usar o backend assíncrono ou síncrono, simplesmente especificando a string de conexão.
RedisBackend¶
| Parâmetro | Tipo | Descrição | Padrão |
|---|---|---|---|
url |
str |
URL do Redis. | 'redis://localhost:6379' |
kwargs |
dict[str, Any] |
Recebe os mesmos argumentos do construtor que redis.client.Redis.from_url. O parâmetro decode_responses sempre será True pois o resultado precisa ser retornado como uma string. |
{} |
AsyncRedisBackend¶
| Parâmetro | Tipo | Descrição | Padrão |
|---|---|---|---|
url |
str |
URL do Redis. | 'redis://localhost:6379' |
kwargs |
dict[str, Any] |
Recebe os mesmos argumentos do construtor que redis.asyncio.client.Redis.from_url. O parâmetro decode_responses sempre será True pois o resultado precisa ser retornado como uma string. |
{} |
Mongo¶
Mongo também oferece suporte a backend assíncrono e síncrono
MongoBackend¶
| Parâmetro | Tipo | Descrição | Padrão |
|---|---|---|---|
host |
str |
URI do MongoDB. | 'localhost' |
database |
str |
Nome do banco de dados de cache. | '.cachetoolz' |
kwargs |
dict[str, Any] |
Toma os mesmos argumentos do construtor que pymongo.mongo_client.MongoClient. |
{} |
AsyncMongoBackend¶
| Parâmetro | Tipo | Descrição | Padrão |
|---|---|---|---|
host |
str |
URI do MongoDB. | 'localhost' |
database |
str |
Nome do banco de dados de cache. | '.cachetoolz' |
kwargs |
dict[str, Any] |
Toma os mesmos argumentos do construtor que pymongo.mongo_client.MongoClient. |
{} |
Coder¶
O objeto codificador é responsável por codificar e decodificar objetos python para json a serem armazenados em cache. Algumas classes já são suportadas, mas se precisar você pode adicionar novos codificadores e decodificadores.
Tipos suportados por padrão:¶
- None
- bytes
- str
- int
- float
- bool
- dict
- set
- frozenset
- list
- tuple # é decodificado para uma lista
- uuid.UUID
- pathlib.Path
- collections.deque
- re.Pattern
- datetime.time
- datetime.date
- datetime.datetime
- datetime.timedelta
- decimal.Decimal
- ipaddress.IPv4Address
- apaddress.IPv4Interface
- apaddress.IPv4Network
- apaddress.IPv6Address
- apaddress.IPv6Interface
- apaddress.IPv6Network
Registrar codificador¶
Você pode cadastrar uma classe para decodificação, ela precisa ter os métodos encode e decode onde o método encode deve ter um parâmetro chamado value e deve ter o tipo anotado.
Esses métodos podem ser instance, @staticmethod ou @classmethod.
A função decodificar receberá o valor exato retornado pela função de codificação.
Métodos de classe
from collections import deque
@coder.register
class DequeCoder:
@classmethod
def encode(cls, value: deque):
return {'iterable': list(value), 'maxlen': value.maxlen}
@classmethod
def decode(cls, value):
return deque(val['iterable'], val['maxlen'])
Métodos estáticos
from collections import deque
@coder.register
class DequeCoder:
@staticmethod
def encode(value: deque):
return {'iterable': list(value), 'maxlen': value.maxlen}
@staticmethod
def decode(value):
return deque(val['iterable'], val['maxlen'])
Métodos de instância
from collections import deque
@coder.register
class DequeCoder:
def encode(self, value: deque):
return {'iterable': list(value), 'maxlen': value.maxlen}
def decode(self, value):
return deque(val['iterable'], val['maxlen'])
Ao registrar uma turma, ela será instanciada. Portanto, se a classe exigir algum parâmetro de inicialização, você poderá registrar uma instância dela junto com os parâmetros necessários.
from collections import deque
class DequeCoder:
def __init__(self, foo):
self.foo = foo
def encode(self, value: deque):
return {'iterable': list(value), 'maxlen': value.maxlen}
def decode(self, value):
return deque(val['iterable'], val['maxlen'])
coder.register(DequeCoder(foo='bar'))
Registrar codificação¶
Caso não haja necessidade de decodificar o resultado ou prefira adicioná-lo separadamente, você tem a opção de cadastrar um único codificador.
from collections import deque
from cachetoolz.coder import encoder
@encoder.register('deque')
def _(value: deque):
return {'iterable': list(value), 'maxlen': value.maxlen}
Registrar decodificação¶
Ao registar um descodificador, é essencial garantir que o nome corresponde ao nome do codificador. Não fazer isso resultará na falta de conexão entre eles.
from collections import deque
from cachetoolz.coder import decoder
@decoder.register('deque')
def _(value):
return deque(value['iterable'], value['maxlen'])