Solution 1

``````class Calculator(object):
def __init__(self):
self.cache = {}

def _find_cached_computation(self, operation, params):
if operation not in self.cache:
return None
for prev_computations in self.cache[operation]:
if prev_computations[:2] == params:
return prev_computations[2]

def _append_to_cache(self, operation, cached_value):
self.cache.setdefault(operation, [])
self.cache[operation].append(cached_value)

if not cached:
cached = x + y
return cached

def subtract(self, x, y):
cached = self._find_cached_computation('subtract', (x, y))
if not cached:
cached = x - y
self._append_to_cache('subtract', (x, y, cached))
return cached
``````

# Cached Calculator

Write a class `Calculator` that has the same methods as the previous one (`add` and `subtract`). But it should also have an attribute `cache` that keeps track of the operations being already performed as a dictionary (see example below and test cases). If the operation was already performed, the method should return the value from the cache. Example:

``````>>> c = Calculator()
>>> c.cache
{}
5
>>> c.cache
{
(2, 3, 5)
]
}
>>> c.subtract(8, 2)
6
>>> c.cache
{
(2, 3, 5)
],
'subtract': [
(8, 2, 6)
]
}
12
>>> c.cache
{
(2, 3, 5),
(9, 3, 12)
],
'subtract': [
(8, 2, 6)
]
}
# Same method invoked again:
>>> c.add(2, 3)  # Should be returned from the cache
5
``````

### Test Cases

test calculator cache -

``````def test_calculator_cache():
c = Calculator()
assert hasattr(c, 'cache')
assert c.cache == {}

assert c.cache == {
(2, 8, 10)
]
}

assert c.subtract(7, 2) == 5
assert c.cache == {
(2, 8, 10)
],
'subtract': [
(7, 2, 5)
]
}

assert c.subtract(11, 7) == 4
assert c.cache == {
(2, 8, 10)
],
'subtract': [
(7, 2, 5),
(11, 7, 4)
]
}

# Repeated operation. Should be cached