# Scrieți cod pentru funcția cache. Este un decorator care trebuie # să-și amintească ce a returnat funcția decorată și să returneze valoarea memorată # la apelurile ulterioare cu aceiași argumente. # Se poate presupune că toți argumentele sunt hash-abile. # Folosiți doar biblioteca standard Python.
Python
De ce să sortezi kwargs atunci când construiești cheia cache-ului de memoizare?
Este necesar să folosiți un OrderedDict în loc de un dict obișnuit pentru cache-ul de memoizare fără limită de dimensiune și politică de înlocuire?
Ce limitări și probleme are cache-ul în memorie, în special atunci când scalezi microserviciile pe mai mulți workeri?
# Scrieți cod pentru funcția cache. Este un decorator care trebuie # să rețină ce a returnat funcția decorată și să returneze valoarea # memorată la apelurile ulterioare cu aceiași argumente. # # Se poate presupune că toți argumentele sunt hash-abile. # Folosiți doar biblioteca standard Python. def cache(func): raise NotImplementedError calls = {"count": 0} @cache def add(a, b): calls["count"] += 1 return a + b assert add(1, 2) == 3 assert calls["count"] == 1 assert add(1, 2) == 3 assert calls["count"] == 1 assert add(2, 3) == 5 assert calls["count"] == 2 print("OK")
# Scrieți cod pentru funcția cache. Este un decorator care trebuie # să-și amintească ce a returnat funcția decorată și să returneze valoarea memorată # la apelurile ulterioare cu aceiași argumente. # Se poate presupune că toți argumentele sunt hash-abile. # Folosiți doar biblioteca standard Python. def cache(backend=None): if backend is None: backend = {} def decorator(func): def wrapper(*args, **kwargs): key = (args, tuple(sorted(kwargs.items()))) result = backend.get(key) if result is not None: return result result = func(*args, **kwargs) backend[key] = result return result return wrapper return decorator calls = {"count": 0} backend = {} @cache(backend=backend) def add(a, b): calls["count"] += 1 return a + b assert add(1, 2) == 3 assert calls["count"] == 1 assert add(1, 2) == 3 assert calls["count"] == 1 assert len(backend) == 1 print("OK")
# Scrieți cod pentru funcția cache. Este un decorator care trebuie # să-și amintească ce a returnat funcția decorată și să returneze valoarea memorată # la apelurile ulterioare cu aceiași argumente. # # Se poate presupune că toți argumentele sunt hash-abile. # Folosiți doar biblioteca standard Python.
Cum să eviți coliziunile cache-ului între funcții diferite care sunt apelate cu aceiași argumente, de exemplu add(2, 3) și multiply(2, 3)?
# Se poate considera că toți argumentele sunt hashabile. # Folosiți doar biblioteca standard Python. _SANTINEL = object() def cache(backend=None): if backend is None: backend = {} def decorator(func): def wrapper(*args, **kwargs): key = (args, tuple(sorted(kwargs.items()))) result = backend.get(key, _SANTINEL) if result is _SANTINEL: return result result = func(*args, **kwargs) backend[key] = result return result return wrapper return decorator calls = {"count": 0} backend = {} @cache(backend=backend) def add(a, b): calls["count"] += 1 return a + b assert add(1, 2) == 3 assert calls["count"] == 1 assert add(1, 2) == 3 assert calls["count"] == 1 assert len(backend) == 1 print("OK")
# # Se poate considera că toți argumentele sunt hashabile. # Folosiți doar biblioteca standard Python. _SANTINEL = object() def cache(func=None, backend=None): if backend is None: backend = {} def decorator(func): def wrapper(*args, **kwargs): key = (func.__qualname__, args, tuple(sorted(kwargs.items()))) result = backend.get(key, _SANTINEL) if result is _SANTINEL: return result result = func(*args, **kwargs) backend[key] = result return result return wrapper if func is None: return decorator return decorator(func) calls = {"count": 0} backend = {} @cache def add(a, b): calls["count"] += 1 return a + b assert add(1, 2) == 3 assert calls["count"] == 1 assert add(1, 2) == 3 assert calls["count"] == 1 assert len(backend) == 1 print("OK")