The thing that you want to do is called "memoization". First of all, in your code the function never actually gets called, you are just storing the function object itself. In order to fix that you need to create a wrapper function inside oncefunc()
and return it:
(here I am not considering the keyword arguments to func
for simplicity)
class Attempt:
def __init__(self, stop):
self.stop = stop
answer = Attempt([])
def oncefunc(func):
def wrapper(*args):
if answer.stop == []:
answer.stop.append(func(*args))
return answer.stop[0]
else:
return answer.stop[0]
return wrapper
def mult(a1, a2):
print("calculating")
return a1 * a2
multonce = oncefunc(mult)
print(multonce(1, 2))
print(multonce(1, 2))
Then we have the next problem: the answer gets stored in the same place for any arguments of func
! So if you call multonce
with different arguments the second time, it will return the same value. This can be fixed by keeping a dictionary with keys being the argument tuples:
class Attempt:
def __init__(self):
self.answers = {}
answer = Attempt()
def oncefunc(func):
def wrapper(*args):
if args not in answer.answers:
answer.answers[args] = func(*args)
return answer.answers[args]
else:
return answer.answers[args]
return wrapper
def mult(a1, a2):
print("calculating")
return a1 * a2
multonce = oncefunc(mult)
print(multonce(1, 2))
print(multonce(1, 2))
print(multonce(3, 4))
And the last thing is that keeping the answer database outside makes it global for all functions wrapped in oncefunc
. It is much more convenient to keep it in a closure, so that it is unique for every application of oncefunc
:
def oncefunc(func):
answers = {}
def wrapper(*args):
if args not in answers:
answers[args] = func(*args)
return answers[args]
else:
return answers[args]
return wrapper
def mult(a1, a2):
print("calculating")
return a1 * a2
multonce = oncefunc(mult)
print(multonce(1, 2))
print(multonce(1, 2))
print(multonce(3, 4))
Of course, this is a very common pattern, so Python already has an implementation of it: lru_cache
:
from functools import lru_cache
@lru_cache(maxsize=None)
def mult(a1, a2):
print("calculating")
return a1 * a2
print(mult(1, 2))
print(mult(1, 2))
print(mult(3, 4))