A proxy can also be a gatekeeper. A protection proxy enforces access rules before letting a call through, and a denied call must never reach the real service at all.
The proxy now takes an optional allowed set of keys. If allowed is None, everything is permitted (the earlier behavior). Otherwise, a fetch for a key outside the allowed set returns None immediately, no cache lookup, no service call, no lazy construction.
Wire the check in first: fetch returns None for a denied key before doing anything else.
class RealService:
def __init__(self, backend):
self.backend = dict(backend)
self.calls = 0
def fetch(self, key):
self.calls += 1
return self.backend.get(key)
class Proxy:
def __init__(self, backend, allowed=None):
self._backend = dict(backend)
self._real = None
self._cache = {}
self._allowed = allowed
def _ensure_real(self):
if self._real is None:
self._real = RealService(self._backend)
def _is_allowed(self, key):
"""True when access is unrestricted or the key is explicitly allowed."""
# TODO: return self._allowed is None or key in self._allowed
pass
def fetch(self, key):
if not self._is_allowed(key):
return None
if key in self._cache:
return self._cache[key]
self._ensure_real()
value = self._real.fetch(key)
self._cache[key] = value
return value
The editor and the test runner need a wide screen. Open this page on a desktop browser and your progress will be waiting.
A proxy can also be a gatekeeper. A protection proxy enforces access rules before letting a call through, and a denied call must never reach the real service at all.
The proxy now takes an optional allowed set of keys. If allowed is None, everything is permitted (the earlier behavior). Otherwise, a fetch for a key outside the allowed set returns None immediately, no cache lookup, no service call, no lazy construction.
Wire the check in first: fetch returns None for a denied key before doing anything else.
Press Run Tests or ββ© to check your solution.